{INCLUDE FILE UABC5 -- IMPLEMENTATION OF UABC}
{Copyright 1983, 1984, Apple Computer, Inc.}

                    {TPanel-TBand-TPane-TMarginPad-TBodyPad-TScroller-TScrollBar}

{changed 05/11/84 11:25 In TPanel.MoveSplitBefore, if we are creating a new split check the new band's
                            ViewLCd after creation; if not the same as what we passed in, invalidate the
                            new band's innerRect.}



{$S sCldInit}
PROCEDURE InvalDiffRect(r1, r2: Rect); {invalidate r1 - r2}
    VAR dummyRect:  Rect;
        rgn1:	    RgnHandle;
        rgn2:	    RgnHandle;

    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        IF EmptyRect(r1) THEN
            {nothing to do}
        ELSE IF SectRect(r1, r2, dummyRect) THEN
            BEGIN
            rgn1 := NewRgn;
            rgn2 := NewRgn;
            RectRgn(rgn1, r1);
            RectRgn(rgn2, r2);
            DiffRgn(rgn1, rgn2, rgn1);
            InvalRgn(rgn1);
            DisposeRgn(rgn1);
            DisposeRgn(rgn2);
            END
        ELSE
            InvalRect(r1);

        {$IFC fTrace}EP;{$ENDC}
    END;


METHODS OF TPanel;


    {$S SgABCini}
    FUNCTION  {TPanel.}CREATE{(object: TObject; heap: THeap; itsWindow: TWindow;
                               minHeight, minWidth: INTEGER; itsVAbilities, itsHAbilities: TAbilities)
                               : TPanel};
        VAR hasWinResize:   BOOLEAN;
            viewedLRect:    LRect;
            panes:	    TList;
            bandOuterRect:  Rect;
            vhs:	    VHSelect;
            scrollBar:	    TScrollBar;
            scroller:	    TScroller;
            band:	    TBand;
            bandList:	    TList {OF TBand};
            aPane:	    TPane;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TPanel(object);

        IF aSplit IN itsVAbilities THEN
            itsVAbilities := itsVAbilities + [aBar];
        IF aSplit IN itsHAbilities THEN
            itsHAbilities := itsHAbilities + [aBar];

        WITH SELF DO
            BEGIN
            window := itsWindow;
            view := NIL;
            currentView := NIL;
            selection := NIL;
            undoSelection := NIL;
            minInnerDiagonal.v := minHeight;
            minInnerDiagonal.h := minWidth;
            abilities[v] := itsVAbilities;
            abilities[h] := itsHAbilities;
            previewMode := mPrvwOff;
            paginatedView := NIL;
            parentBranch := NIL;
            resizeBranch := NIL;
            scrollBars[v] := NIL; {so GetBorder (called by SetOuterRect below) won't blow up}
            scrollBars[h] := NIL; {ditto}

            {$H-}
            SetPt(tlSideBandSize, -1, -1); {+++ LSR +++}
            SetPt(brSideBandSize, -1, -1); {+++ LSR +++}
            {$H+}

            deletedSplits := NIL;
            END;

        SELF.zoomed := FALSE;
        WITH SELF.zoomFactor DO
      {$H-} BEGIN
            SetPt(numerator, 1, 1);
            SetPt(denominator, 1, 1);
      {$H+} END;

        SELF.SetOuterRect(itsWindow.outerRect);

        noPad.RectToLRect(SELF.innerRect, viewedLRect);
        panes := TList.CREATE(NIL, heap, 1);
        SELF.panes := panes;
        aPane := SELF.NewPane(heap, SELF.innerRect, viewedLRect);
        WITH SELF.lastClick DO
            BEGIN
            gotPane := TRUE;
            clickPane := aPane;
            END;
        SELF.panes.InsLast(aPane);

        bandOuterRect := SELF.innerRect;
        InsetRect(bandOuterRect, -1, -1);

        FOR vhs := v TO h DO
            BEGIN
            scrollBar := TScrollBar.CREATE(NIL, heap, vhs, bandOuterRect, aBar IN SELF.abilities[vhs]);
            SELF.scrollBars[vhs] := scrollBar;
            scroller := scrollBar.firstBox;
            band := SELF.NewBand(heap, SELF.innerRect, scroller, vhs);
            band.panes.InsLast(SELF.panes.First);
            bandList := TList.CREATE(NIL, heap, 1);
            bandList.InsLast(band);
            SELF.bands[vhs] := bandList;
            END;

        IF itsWindow.panelTree = NIL THEN {The first panel gets inserted automatically}
            BEGIN
            itsWindow.panelTree := SELF;
            itsWindow.panels.InsLast(SELF);

            itsWindow.selectPanel := SELF;
            itsWindow.clickPanel := SELF;

            SELF.DecideAboutBars(SELF.outerRect);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCini}
    PROCEDURE {TPanel.}Free;
        VAR vhs: VHSelect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        Free(SELF.selection);
        Free(SELF.undoSelection);
        Free(SELF.view);
        IF SELF.currentView <> SELF.view THEN
            Free(SELF.currentView);
        FOR vhs := v TO h DO
            BEGIN
            SELF.bands[vhs].Free;
            SELF.scrollBars[vhs].Free;
            END;
        SELF.panes.Free;
        Free(SELF.deletedSplits);
        TArea.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TPanel.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TArea.Fields(Field);
        Field('window: TWindow');
        Field('panes: TList');
        Field('currentView: TView');
        Field('view: TView');
        Field('paginatedView: TPaginatedView');
        Field('selection: TSelection');
        Field('undoSelection: TSelection');
        Field('bands: ARRAY [0..1] OF TList');
        Field('scrollBars: ARRAY [0..1] OF TScrollBar');
        Field('abilities: ARRAY [0..1] OF Byte');
        Field('minInnerDiagonal: Point');
        Field('resizeBranch: TBranchArea');
        Field('zoomed: BOOLEAN');
        Field('zoomFactor: RECORD numerator: Point; denominator: Point END');
        Field('previewMode: Byte');
        Field('');
        Field('lastClick: RECORD gotPane: BOOLEAN; clickPane: TPane; END');
        Field('contentRect: Rect');
        Field('tlSideBandSize: Point');
        Field('brSideBandSize: Point');
        Field('deletedSplits: TArray');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sRes}
    PROCEDURE {TPanel.}AutoScroll{(mousePt: Point)};
        VAR vhs:        VHSelect;
            mouseCd:    INTEGER;
            f:	        INTEGER;
            deltaLPt:   LPoint;
            pane:       TPane;
            r:	        Rect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.currentView.GetStdScroll(deltaLPt);
        FOR vhs := v TO h DO
            BEGIN
            mouseCd := mousePt.vh[vhs];
            IF NOT (aScroll IN SELF.abilities[vhs]) THEN
                f := 0
            ELSE
            IF mouseCd < SELF.contentRect.topLeft.vh[vhs] THEN {+++ LSR +++}
                f := -1
            ELSE
            IF mouseCd > SELF.contentRect.botRight.vh[vhs] THEN {+++ LSR +++}
                f := 1
            ELSE
                f := 0;
            deltaLPt.vh[vhs] := f * deltaLPt.vh[vhs];
            END;

        {Find the pane to scroll; make sure it is not in a side band}
        r := SELF.contentRect;
        InsetRect(r, 1, 1); {Because the outerRects of a side band's panes overlap the contentRect by 1 pixel;
                                (ChildWithPt checks the outerRect)}
        RectHavePt(r, mousePt);
        pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, mousePt));
        pane.ScrollBy(deltaLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TPanel.}BeginSelection;	 {+SW+}
        VAR thisWindow:	        TWindow;
            companionWindow:    TWindow;
        PROCEDURE DeselPanel(obj: TObject);
        BEGIN
            TPanel(obj).selection.Deselect;
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.BeSelectPanel(TRUE);
        thisWindow := SELF.window;
        companionWindow := NIL;
        IF thisWindow = currentWindow THEN
            companionWindow := thisWindow.dialogBox {+SW+}
        ELSE
        IF thisWindow = currentWindow.dialogBox THEN
            IF currentWindow.dialogBox.downInMainWindowResponse = diGiveToMainWindow THEN
                companionWindow := currentWindow;

        IF companionWindow <> NIL THEN
            BEGIN
            PushFocus;
            companionWindow.Focus;
            companionWindow.panels.Each(DeselPanel);
            PopFocus;
            END;
        thisWindow.panels.Each(DeselPanel);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TPanel.}BeSelectPanel{(inSelectWindow: BOOLEAN)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF inSelectWindow THEN
            currentWindow.selectWindow := SELF.window;
        SELF.window.selectPanel := SELF;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TPanel.}CleanUpPanes{(deleteList: TList)};
        VAR s:	    TListScanner;
            pane:   TPane;
            bs:	    TListScanner;
            band:   TBand;
            vhs:    VHSelect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.lastClick.gotPane THEN
            IF deleteList.Pos(0, SELF.lastClick.clickPane) > 0 THEN
                WITH SELF.lastClick DO
                    BEGIN
                    gotPane := FALSE;
                    clickPt := clickPane.innerRect.topLeft;  {+}
                    END;

        s := deleteList.Scanner;
        WHILE s.Scan(pane) DO
            BEGIN
            SELF.panes.DelObject(pane, FALSE);
            FOR vhs := v To h DO
                BEGIN
                bs := SELF.bands[vhs].Scanner;
                WHILE bs.Scan(band) DO
                    band.panes.DelObject(pane, FALSE);
                END;
            END;
        deleteList.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}



    {$S sRes}
    PROCEDURE {TPanel.}ComputeContentRect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        WITH SELF DO
            BEGIN
            {$H-}
            contentRect.topLeft := Point(FPtPlusPt(innerRect.topLeft, tlSideBandSize));
            contentRect.botRight := Point(FPtMinusPt(innerRect.botRight, brSideBandSize));

            InsetRect(contentRect, 1, 1);
            {$H+}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    FUNCTION  {TPanel.}CursorAt{(mousePt: Point): TCursorNumber};
        VAR pane:       TPane;
            nearestPt:  Point;
    BEGIN
        {$IFC fTrace}BP(2);{$ENDC}
        IF NOT RectHasPt(SELF.outerRect, mousePt) THEN
            CursorAt := noCursor
        ELSE
        IF currentDocument = clipboard THEN
            CursorAt := arrowCursor
        ELSE
        IF RectHasPt(SELF.innerRect, mousePt) THEN
            BEGIN
            pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, nearestPt));
            CursorAt := pane.CursorAt(mousePt);
            END
        ELSE
            CursorAt := arrowCursor;
    {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCini}
    PROCEDURE {TPanel.}DecideAboutBars{(newOuterRect: Rect)};
        VAR branch:	    TBranchArea;
            needsBothBars:  BOOLEAN;
            vhs:	    VHSelect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        branch := SELF.FindBranchThatIsResized;
        SELF.resizeBranch := branch;
        needsBothBars := (branch <> NIL) OR
            (EqualPt(newOuterRect.botRight, SELF.window.outerRect.botRight) AND SELF.window.isResizable);
        FOR vhs := v TO h DO
            SELF.scrollBars[vhs].ChangeVisibility(needsBothBars, zeroRect, SELF.abilities[vhs]);
        SELF.SetOuterRect(newOuterRect);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    FUNCTION  {TPanel.}Divide{(vhs: VHSelect;
                               fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
                               whoCanResizeIt: TResizability;
                               minSize: INTEGER; itsVAbilities, itsHAbilities: TAbilities): TPanel};

        VAR itsMinInnerDiag:    Point;
            panel:	        TPanel;	    {the new panel}

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        itsMinInnerDiag := SELF.minInnerDiagonal;
        itsMinInnerDiag.vh[vhs] := minSize;

        panel := TPanel.CREATE(NIL, SELF.heap, SELF.window,
                               itsMinInnerDiag.v, itsMinInnerDiag.h, itsVAbilities, itsHAbilities);

        SELF.Insert(panel, vhs, fromEdgeOfPanel, units, whoCanResizeIt);

        Divide := panel;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sScroll}
    PROCEDURE {TPanel.}DoScrolling{(inArea: TArea; itsPane: TPane;
                            hOk, vOk: BOOLEAN; VAR deltaLPt: LPoint)};
            {positive scrolls towards end, (0,0) means invalidate only;
                if inArea is a pane then itsPane=inArea
                if inArea is a band then itsPane is any one of the band's panes;
                hOk & vOk indicate whether scrolling is allowed in that direction;
                deltaLPt is set to amount actually scrolled by;

            NOTE: assumes we are focused on something at least as big as inArea. }
        VAR viewedLRect:        LRect;
            resizing:	        BOOLEAN;
            scrollableLRect:    LRect;
            freedomLRect:       LRect;
            deltaPt:	        Point;
            vhs:	        VHSelect;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        resizing := EqualLPt(deltaLPt, zeroLPt);

        itsPane.GetScrollLimits(viewedLRect, scrollableLRect);

        LRectMinusLRect(scrollableLRect, viewedLRect, freedomLRect);
        LRectHaveLPt(freedomLRect, deltaLPt);

        IF NOT hOk THEN
            deltaLPt.h := 0;
        IF NOT vOK THEN
            deltaLPt.v := 0;

        IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
            BEGIN
            IF resizing OR NOT IsSmallPt(deltaLPt) THEN
                InvalRect(inArea.innerRect)
            ELSE
                BEGIN
                itsPane.LDistToDist(deltaLPt, deltaPt);
                ScrollRect(inArea.innerRect, -deltaPt.h, -deltaPt.v, scrollRgn);
                InvalRgn(scrollRgn);
                END;
           END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TPanel.}DownAt{(mousePt: Point): BOOLEAN};
        VAR found:	    BOOLEAN;
            cantDown:	    BOOLEAN;
            vhs:	    VHSelect;
            outerRect:	    Rect;
            innerRect:	    Rect;
            insetContent:   Rect;
            growRect:	    Rect;
            window:	    TWindow;
            dialogBox:	    TDialogBox;
            icon:	    TEnumIcons;
            scroller:	    TScroller;
            pane:	    TPane;
            viewedLRect:    LRect;
            hysteresis:	    BOOLEAN;
            limitRect:	    Rect;
            hysterPt:	    Point;
            origPt:	    Point;
            diffPt:	    Point;
            nearestPt:	    Point;
            aheadEvent:	    EventRecord;
            destPanel:	    TPanel;
            destView:	    TView;
            lPtInView:	    LPoint;
            received:	    BOOLEAN;
            mouseInContent: BOOLEAN; {TRUE iff mouse is currently in contentRect}

        PROCEDURE EnforceHysteresis;
            BEGIN
            diffPt := Point(FPtMinusPt(mousePt, origPt));
            SELF.selection.GetHysteresis(hysterPt);
            IF (ABS(diffPt.h) < hysterPt.h) AND (ABS(diffPt.v) < hysterPt.v) THEN
                mousePt := origPt
            ELSE
                hysteresis := FALSE;
            END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        outerRect := SELF.outerRect;
        innerRect := SELF.innerRect;
        insetContent := SELF.contentRect;
        InsetRect(insetContent, 1, 1);

        IF NOT RectHasPt(innerRect, mousePt) THEN  {+}
            BEGIN
            found := FALSE;
            FOR vhs := v TO h DO
                IF NOT found THEN
                    IF SELF.scrollBars[vhs].DownAt(mousePt, scroller, icon) THEN
                        BEGIN
                        SELF.HitScroller(vhs, mousePt, scroller, icon);
                        found := TRUE;
                        END;
            IF NOT found THEN
                BEGIN
                SetRect(growRect, innerRect.right + 1, innerRect.bottom + 1,
                                  outerRect.right - 1, outerRect.bottom - 1);
                IF RectHasPt(growRect, mousePt) THEN
                    BEGIN
                    SELF.DownInSizeBox(mousePt);
                    found := TRUE;
                    process.RememberCommand(uResizePanel);
                    END;
                END;

            DownAt := found;
            END
        ELSE
            BEGIN
            DownAt := TRUE;
            IF currentDocument = clipboard THEN
                process.Stop(phEditClip)
            ELSE
                BEGIN
                window := SELF.window;
                dialogBox := window.dialogBox;
                IF dialogBox = NIL THEN
                    cantDown := FALSE
                ELSE
                IF dialogBox.downInMainWindowResponse = diDismissDialogBox THEN
                    BEGIN
                    dialogBox.BeDismissed;
                    cantDown := FALSE;
                    END
                ELSE
                    cantDown := (dialogBox.downInMainWindowResponse = diRefuse);

                IF cantDown THEN
                    process.Stop(phDialogUp)

                ELSE

                    BEGIN
                    {$IFC fDbgABC}
                    IF SELF.currentView = NIL THEN
                        ABCBreak('DownAt with no view set', 0);
                    {$ENDC}

                    mouseInContent := RectHasPt(insetContent, mousePt);

                    pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, nearestPt));
                    IF mouseInContent THEN
                        WITH SELF.lastClick DO
                            BEGIN
                            gotPane := TRUE;
                            clickPane := pane;
                            END;

                    process.RememberCommand(uMousePress);
                    pane.MouseTrack(mPress, mousePt);

                    IF SELF.selection.canCrossPanels THEN
                        BEGIN
                        pane.RectToLRect(window.innerRect, viewedLRect);

                        WITH pane.origin DO {$H-} {convert to (0,0)-origined view coordinates}
                            OffsetLRect(viewedLRect, h, v); {$H+}

                        pane := TPane.CREATE(NIL, SELF.Heap, SELF, window.innerRect, viewedLRect);
                        PushFocus;
                        pane.Focus;
                        SELF.selection.DrawGhost;
                        PopFocus;
                        END;

                    {Set up some temporaries for the StillDown loop}
                    limitRect := SELF.contentRect;   {AutoScroll slop}
                    InsetRect(limitRect, -9, -6);  {*** should be more lenient at edges of screen ***}
                    origPt := mousePt;
                    hysteresis := TRUE;

                    WHILE stillDown do
                        BEGIN
                        GetMouse(mousePt);
                        {use pane.outerRect in line below, because ChildWithPt checks the outerRect}
                        IF NOT (RectHasPt(pane.outerRect, mousePt) OR SELF.selection.canCrossPanels) THEN
                            BEGIN
                            IF mouseInContent THEN {autoscrolling allowed}
                                BEGIN
                                IF NOT RectHasPt(limitRect, mousePt) THEN
                                    BEGIN
                                    SELF.AutoScroll(mousePt);
                                    window.Update(TRUE);
                                    END;
                                RectHavePt(insetContent, mousePt); {force mouse point into contentRect}
                                END;

(**** Do we want this line? Depend on if you want to allow people to down in side band, move into content
        and go back to side band
                            mouseInContent := RectHasPt(insetContent, mousePt);
****)
                            pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, mousePt));
                            hysteresis := FALSE;
                            END
                        ELSE
                        IF hysteresis THEN
                            EnforceHysteresis;
                        pane.MouseTrack(mMove, mousePt);
                        END;

                    IF PeekEvent(aheadEvent) THEN
                        BEGIN
                        IF aheadEvent.what = buttonUp THEN
                            BEGIN
                            mousePt := aheadEvent.where; {otherwise, use last polled point}

                            {check to see if we've crossed the pane boundary
                             use pane.outerRect in line below, because ChildWithPt checks the outerRect}
                            IF NOT (RectHasPt(pane.outerRect, mousePt) OR
                                    SELF.selection.canCrossPanels) THEN
                                BEGIN
                                IF mouseInContent THEN  {force mouse point into contentRect}
                                    RectHavePt(insetContent, mousePt);

                                pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, mousePt));
                                hysteresis := FALSE;
                                END;
                            RectHavePt(pane.innerRect, mousePt);
                            END;

                        IF hysteresis THEN
                            EnforceHysteresis;
                        END;

                    pane.MouseTrack(mRelease, mousePt);

                    IF SELF.selection.canCrossPanels THEN
                        BEGIN
                        pane.Free;
                        destPanel := TPanel(window.ChildWithPt(mousePt, window.panels, nearestPt));
                        IF PtInRect(mousePt, destPanel.innerRect) THEN
                            BEGIN
                            destView := destPanel.view;
                            pane := TPane(destPanel.ChildWithPt(mousePt, destPanel.panes, nearestPt));

                            {Account for origin difference between window and pane}
                            PushFocus;
                            LocalToGlobal(mousePt);
                            pane.Focus;
                            GlobalToLocal(mousePt);
                            pane.PtToLpt(mousePt, lPtInView);
                            received := destView.DoReceive(SELF.selection, lPtInView);
                            PopFocus;
                            END
                        ELSE
                            received := FALSE;
                        IF NOT received THEN
                            SELF.selection.MoveBackToAnchor;
                        END;
                    END;
                END;
            END;
    {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S sRes}
    PROCEDURE {TPanel.}DownInSizeBox{(mousePt: Point)};
        VAR branch:	    TBranchArea;
            outerRect:	    Rect;
            oldTopLeft:	    Point;
            oldBotRight:    Point;
            vhs:	    VHSelect;
            minPt:	    Point;
            maxPt:	    Point;
            elderFirst:	    BOOLEAN;
            minExtents:	    ARRAY [FALSE..TRUE] OF Point;
            newBotRight:    Point;
            newCd:	    INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        branch := SELF.resizeBranch;
        IF branch <> NIL THEN
            BEGIN
            outerRect := branch.outerRect;
            oldTopLeft := outerRect.topLeft;
            oldBotRight := outerRect.botRight;
            vhs := branch.arrangement;

            {don't resize in the orthogonal direction}
            minPt := oldBotRight;
            maxPt := oldBotRight;

            {limit resizing in the free direction}
            elderFirst := branch.elderFirst;
            branch.elderChild.GetMinExtent(minExtents[elderFirst], FALSE);
            branch.youngerChild.GetMinExtent(minExtents[NOT elderFirst], FALSE);
            minPt.vh[vhs] := oldTopLeft.vh[vhs]	 + minExtents[TRUE].vh[vhs];
            maxPt.vh[vhs] := oldBotRight.vh[vhs] - minExtents[FALSE].vh[vhs];

            {let the user specify the new botRight}
            ResizeFeedback(mousePt, minPt, maxPt, branch.TopLeftChild.outerRect,
                                0, dhSBox, dvSBox, newBotRight);

            newCd := newBotRight.vh[vhs];
            IF newCd <> oldBotRight.vh[vhs] THEN
                branch.Redivide(newCd);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TPanel.}FindBranchThatIsResized{: TBranchArea};
        VAR child:      TArea;
            fini:       BOOLEAN;
            parent:     TBranchArea;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        { Find the panel branch of which this is the bottom right corner of the top left child }
        child := SELF;
        fini := FALSE;
        REPEAT
            parent := child.parentBranch;
            IF parent = NIL THEN
                fini := TRUE
            ELSE
                fini := parent.TopLeftChild = child;
            child := parent;
          UNTIL fini;

        FindBranchThatIsResized := NIL;
        IF parent <> NIL THEN
            IF userCanResizeIt IN parent.resizability THEN
                FindBranchThatIsResized := parent;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TPanel.}Frame;
        VAR actively:   BOOLEAN;
            growRect:   Rect;
            branch:     TBranchArea;
            vhs:        VHSelect;
            {$IFC LibraryVersion > 20}
            icon:       Char;
            {$ENDC}
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF NOT RectsNest(SELF.innerRect, focusRgn^^.rgnBBox) THEN
            BEGIN
            TArea.Frame;
            actively := SELF.window.IsActive;

            IF SELF.scrollBars[v].isVisible OR SELF.scrollBars[h].isVisible THEN
                IF NOT EqualPt(SELF.outerRect.botRight, SELF.window.outerRect.botRight) THEN
                    BEGIN   {Draw the panel's resize box}
                    SetRect(growRect, SELF.innerRect.right, SELF.innerRect.bottom,
                                      SELF.outerRect.right, SELF.outerRect.bottom);
                    FillRect(growRect, white);
                    IF actively THEN
                        BEGIN
                        branch := SELF.resizeBranch;
                        IF branch <> NIL THEN   {Draw a resize icon in the box}
                            BEGIN
                            {$IFC LibraryVersion <= 20}
                            vhs := branch.arrangement;
                            InsetRect(growRect, 3, 2);
                            growRect.botRight.vh[vhs] := growRect.topLeft.vh[vhs] + 1;
                            PenNormal;
                            FrameRect(growRect);
                            {$ELSEC}
                            TextFont(wmFont);
                            TextFace([]);
                            MoveTo(growRect.left, growRect.top);
                            IF branch.arrangement = v THEN
                                icon := CHR(33)
                            ELSE
                                icon := CHR(34);
                            DrawChar(icon);
                            {$ENDC}
                            END;
                        END;
                    END;

            FOR vhs := v TO h DO
                IF actively THEN
                    SELF.scrollBars[vhs].Draw
                ELSE
                    SELF.scrollBars[vhs].Erase;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S sRes}
    PROCEDURE {TPanel.}GetBorder{(VAR border: Rect)};
        VAR vhs:    VHSelect;
            hasBar: BOOLEAN;
            d:	    ARRAY[VHSelect] OF INTEGER;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        FOR vhs := v TO h DO
            BEGIN
            IF SELF.scrollBars[vhs] = NIL THEN
                hasBar := FALSE
            ELSE
                hasBar := SELF.scrollBars[orthogonal[vhs]].isVisible;

            IF hasBar THEN
                d[vhs] := dptSbox.vh[vhs]
            ELSE
            IF SELF.outerRect.botRight.vh[vhs] = SELF.window.outerRect.botRight.vh[vhs] THEN
                d[vhs] := 1
            ELSE
                d[vhs] := 0;
            END;
        SetRect(border, -1, -1, d[h], d[v]);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TPanel.}GetMinExtent{(VAR minExtent: Point; windowIsResizingIt: BOOLEAN)};
        VAR borderRect:	    Rect;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        RectMinusRect(SELF.outerRect, SELF.contentRect, borderRect);
        minExtent := Point(FPtPlusPt(SELF.minInnerDiagonal, Point(FDiagRect(borderRect))));
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TPanel.}HaveView{(view: TView)};
        VAR s:	        TListScanner;
            pane:       TPane;
            selection:  TSelection;
            saveMode:   TPreviewMode;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        saveMode := SELF.previewMode;
        SELF.previewMode := mPrvwOff;
        SELF.view := view;
        SELF.currentView := view;

        s := SELF.panes.Scanner;
        WHILE s.Scan(pane) DO
            pane.HaveView(view);

        view.BeInPanel(SELF);

        IF SELF.selection = NIL THEN
            BEGIN
            selection := view.NoSelection;
            SELF.selection := selection;
            END
        ELSE
            SELF.selection.HaveView(view);

        IF SELF.undoSelection = NIL THEN
            BEGIN
            selection := view.NoSelection;
            SELF.undoSelection := selection;
            END
        ELSE
            SELF.undoSelection.HaveView(view);

        SELF.Preview(saveMode);

        SELF.ResizeInside(SELF.innerRect); {mainly needed to force panes of a new one-panel window to size}

        IF view.isPrintable THEN
            IF SELF.window.panelToPrint = NIL THEN
                SELF.window.panelToPrint := SELF;

        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sRes}
    PROCEDURE {TPanel.}Highlight{(selection: TSelection; highTransit: THighTransit)};

        PROCEDURE HiliteOnThePad;
        BEGIN
            selection.Highlight(highTransit);
        END;

    BEGIN
        {$IFC fMaxTrace}BP(1);{$ENDC}
        {$IFC fMaxTrace}EP;{$ENDC}
        SELF.OnAllPadsDo(HiliteOnThePad);
    END;
{$S SgABCres}


    {$S sScroll}
    PROCEDURE {TPanel.}HitScroller{(vhs: VHSelect; mousePt: Point; scroller: TScroller; icon: TEnumIcons)};
        VAR oldThumbPos:    INTEGER;
            newThumbPos:    INTEGER;
            deltaLStd:	    LPoint;
            band:	    TBand;
            newSkwrCd:	    INTEGER;
            aScroller:	    TScroller;
            prevScroller:   TScroller;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        band := scroller.band;
        CASE icon OF
            iSkewer:
                BEGIN
                scroller.TrackSkewer(mousePt, newSkwrCd, aScroller, prevScroller);
                SELF.MoveSplitBefore(scroller, newSkwrCd);
                process.RememberCommand(uSplitting);
                END;
            iThumb:
                BEGIN
                scroller.TrackThumb(mousePt, oldThumbPos, newThumbPos);
                IF oldThumbPos <> newThumbPos THEN
                    BEGIN
                    band.ThumbTo(newThumbPos);
                    scroller.MoveThumb(band.ThumbPos);
                    END;
                process.RememberCommand(uThumbing);
                END;
            iScrollBack, iScrollFwd, iFlipBack, iFlipFwd:
                BEGIN
                scroller.FillIcon(icon, TRUE);
                SELF.currentView.GetStdScroll(deltaLStd);
                SetupMvThumb(POINTER(scroller.sBoxID));
                REPEAT
                    band.ScrollStep(icon, deltaLStd.vh[vhs]);
                    SELF.window.Update(TRUE);
                    PenNormal;
                    MoveThumb(band.ThumbPos);
                UNTIL NOT StillDown;
                scroller.FillIcon(icon, FALSE);
                process.RememberCommand(uScrolling);
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TPanel.}Insert{(panel: TPanel; vhs: VHSelect;
                               fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
                               whoCanResizeIt: TResizability)};

        VAR window:	        TWindow;
            elderFirst:	        BOOLEAN;    {TRUE if fromEdgeOfPanel<0 (new panel below or to right of old)}
            myOuterRect:        Rect;	    {SELF.outerRect}
            mySize:	        INTEGER;    {Length of SELF beforehand}
            itsOuterRect:       Rect;	    {will be panel.outerRect}
            newSize:	        INTEGER;    {Proposed length of the new panel (in the vh direction)}
            cdInWindow:	        INTEGER;    {the coordinate of myOuterRect that is changing}
            myFormerParent:     TBranchArea;
            ourNewParent:       TBranchArea;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        window := SELF.window;
        window.panels.InsLast(panel);
        panel.window := window;

        elderFirst := fromEdgeOfPanel < 0;
        myOuterRect := SELF.outerRect;
        mySize := LengthRect(myOuterRect, vhs);
        itsOuterRect := myOuterRect;

        newSize := ABS(fromEdgeOfPanel);

        IF units = percentFromEdge THEN	  {convert to pixelsFromEdge}
            newSize := LIntDivInt(LIntMulInt(mySize, newSize), 100);

        newSize := Max(1, Min(newSize, myOuterRect.botRight.vh[vhs] - myOuterRect.topLeft.vh[vhs] - 1));

        IF elderFirst THEN
            newSize := -newSize;

        cdInWindow := TRectCoords(myOuterRect)[elderFirst].vh[vhs] + newSize;
        TRectCoords(myOuterRect)[elderFirst].vh[vhs] := cdInWindow;
        TRectCoords(itsOuterRect)[NOT elderFirst].vh[vhs] := cdInWindow;

        myFormerParent := SELF.parentBranch;

        ourNewParent := TBranchArea.CREATE(NIL, SELF.Heap, vhs, elderFirst, whoCanResizeIt, SELF, panel);

        IF myFormerParent = NIL THEN
            window.panelTree := ourNewParent
        ELSE
            myFormerParent.ReplaceChild(SELF, ourNewParent);

        panel.SetOuterRect(zeroRect); {since the panel is not on the screen right now,
                                            it shouldn't have any size}
        panel.ResizeOutside(itsOuterRect);
        SELF.ResizeOutside(myOuterRect);

        {Just in case some panel is below its mimimum size, let the window expand if needed}
        window.Resize(FALSE);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgDRWres}
    PROCEDURE {TPanel.}Invalidate;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        PushFocus;
        SELF.window.Focus;
        InvalRect(SELF.innerRect);
        PopFocus;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCres}
    PROCEDURE {TPanel.}InvalLRect{(lRectInView: LRect)};

        PROCEDURE InvalOnThePad;
        BEGIN
            thePad.InvalLRect(lRectInView);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.OnAllPadsDo(InvalOnThePad);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TPanel.}MakeBand{(vhs: VHSelect; scroller, prevScroller: TScroller)};
        VAR prevBand:   TBand;
            band:       TBand;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        prevBand := prevScroller.band;
        band := SELF.NewBand(SELF.Heap, zeroRect, scroller, vhs);
        band.panes.Become(prevBand.panes.Clone(SELF.Heap));
        SELF.bands[vhs].InsAt(SELF.bands[vhs].Pos(0, prevBand) + 1, band);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sSplit}
    PROCEDURE {TPanel.}MoveSplitBefore{(scroller: TScroller; newSkwrCd: INTEGER)};
        VAR vhs:		        VHSelect;
            outsideContent:	        BOOLEAN;
            hsb:		        THsb;
            prevHsb:		        THsb;
            prevScroller:	        TScroller;
            nextScroller:	        TScroller;
            otherBand:		        TBand;
            band:		        TBand;
            oldSkwrCd:		        INTEGER;
            newViewLCd:		        LONGINT;
            viewDeltaLCd:	        LONGINT;   {-gb}
            sbRect:		        Rect;
            newSkwrPt:		        Point;
            sbList:		        TSbList;
            limitRect:		        Rect;
            r:			        Rect;

        PROCEDURE InvalScrollers(firstBand, lastBand: TBand);
            VAR firstSbRect:    Rect;
                lastSbRect:     Rect;
        BEGIN
            firstBand.scroller.GetSize(firstSbRect);
            lastBand.scroller.GetSize(lastSbRect);
            UnionRect(firstSbRect, lastSbRect, firstSbRect);
            InvalRect(firstSbRect);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        vhs := scroller.ScrollDir;

        outsideContent := TRUE;
        WITH SELF.contentRect DO
            IF newSkwrCd <= topLeft.vh[vhs] THEN
                newSkwrCd := topLeft.vh[vhs] - 1
            ELSE IF newSkwrCd >= botRight.vh[vhs] THEN
                newSkwrCd := botRight.vh[vhs] + 1
            ELSE
                outsideContent := FALSE;

        hsb := Pointer(scroller.sBoxID);
        prevHsb := HsbPrev(hsb);

        IF prevHsb = hsbNil THEN
            BEGIN
            prevScroller := NIL;

            {make scroller refer to the scroller we are going to split}
            scroller.GetSize(sbRect);
            newSkwrPt.vh[vhs] := newSkwrCd;
            newSkwrPt.vh[orthogonal[vhs]] := sbRect.topLeft.vh[orthogonal[vhs]];

            PreSbList(sbList, scroller.scrollBar);
            hsb := HsbFromPt(sbList, newSkwrPt);
            PostSbList(sbList, scroller.scrollBar);

            IF (hsb = hsbNil)  {user started to create a new split but changed his mind} OR
               outsideContent {new split would be in a side band} THEN
                scroller := NIL {user started to create a new split but changed his mind}
            ELSE
                scroller := TScroller(RefconSb(hsb));
            END
        ELSE
            BEGIN
            prevScroller := TScroller(RefconSb(prevHsb));

            {don't allow the new position of split to cross another split}
            FixRLimits(hsb, limitRect);
            WITH limitRect DO
                newSkwrCd := Max(topLeft.vh[vhs], Min(botRight.vh[vhs], newSkwrCd));
            END;


        IF scroller <> NIL THEN
            BEGIN
            scroller.GetSize(sbRect);
            oldSkwrCd := sbRect.topLeft.vh[vhs];

            WITH SELF.contentRect DO
                IF oldSkwrCd <= topLeft.vh[vhs] THEN
                    oldSkwrCd := topLeft.vh[vhs] - 1
                ELSE IF oldSkwrCd >= botRight.vh[vhs] THEN
                    oldSkwrCd := botRight.vh[vhs] + 1;

            IF newSkwrCd <> oldSkwrCd THEN
                BEGIN
                band := scroller.band;
                viewDeltaLCd := newSkwrCd - oldSkwrCd;						   {-gb}
                IF SELF.zoomed THEN     { if zoomed then adjust viewDeltaLCd accordingly }	   {-gb}
                    WITH SELF.zoomFactor DO							   {-gb}
           {$H-}        viewDeltaCd := LIntOvrInt(LIntMulInt(viewDeltaLCd, denominator.vh[vhs]),
                                                  {-gb +++LSR+++} numerator.vh[vhs]);
           {$H-}
                newViewLCd := band.ViewLCd + viewDeltaLCd;
                IF prevScroller = NIL THEN
                    BEGIN {new band}
                    IF hsb <> hsbNil THEN
                        BEGIN
                        InvalScrollers(band, band);

                        scroller.SplitAt(newSkwrCd, nextScroller);

                        SELF.ResizeBand(vhs, band, band.ViewLCd, FALSE);
                        SELF.MakeBand(vhs, nextScroller, scroller);
                        otherBand := nextScroller.band;
                        SELF.ResizeBand(vhs, otherBand, newViewLCd, FALSE);

                        {must invalidate now (special case)}
                        IF otherBand.ViewLCd <> newViewLCd THEN {the new band scrolled a bit}
                            InvalRect(otherBand.innerRect);

                        Pt2Rect(band.innerRect.botRight, otherBand.innerRect.topLeft, r);
                        InvalRect(r);

                        SELF.RepaneOrthogonalBands(vhs);
                        SELF.RemakePanes;
                        END;
                    END
                ELSE
                    BEGIN {resize or delete band}
                    {If new position of split is outside the contentRect, make it go away}
                    IF outsideContent THEN
                        WITH limitRect DO
                            IF newSkwrCd <= SELF.contentRect.topLeft.vh[vhs] THEN
                                newSkwrCd := topLeft.vh[vhs]
                            ELSE
                                newSkwrCd := botRight.vh[vhs];

                    scroller.ResplitAt(newSkwrCd, prevScroller);
                    otherBand := prevScroller.band;
                    InvalScrollers(otherBand, band);

                    SELF.ResizeBand(vhs, otherBand, otherBand.ViewLCd, TRUE);
                    SELF.ResizeBand(vhs, band, newViewLCd, TRUE);
                    END;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    FUNCTION  {TPanel.}NewBand{(heap: THeap; myInnerRect: Rect;
                                scroller: TScroller; vhs: VHSelect): TBand};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        NewBand := TBand.CREATE(NIL, heap, SELF, myInnerRect, scroller, vhs);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    FUNCTION {TPanel.}NewStatusView{(object: TObject; itsExtent: LRect): TView};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        NewStatusView := TView.CREATE(object, SELF.Heap,  SELF, itsExtent, NIL, zeroLRect,
                                      FALSE, screenRes, TRUE);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    FUNCTION {TPanel.}NewView{(object: TObject; itsExtent: LRect; itsPrintManager: TPrintManager;
                               itsDfltMargins: LRect; itsFitPerfectlyOnPages: BOOLEAN): TView};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        NewView := TView.CREATE(object, SELF.Heap,  SELF, itsExtent, itsPrintManager, itsDfltMargins,
                        itsFitPerfectlyOnPages, screenRes, TRUE);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sStartup}
    FUNCTION  {TPanel.}NewPane{(heap: THeap; innerRect: Rect; viewedLRect: LRect): TPane};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        NewPane := TPane.CREATE(NIL, heap, SELF, innerRect, viewedLRect);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    FUNCTION  {TPanel.}OKToDrawIn{(lRectInView: LRect): BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF NOT SELF.view.OKToDrawIn(lRectInView) THEN
            OKToDrawIn := FALSE
        ELSE
        IF SELF.previewMode = mPrvwBreaks THEN
            OKToDrawIn := FALSE {This will be smarter some day}
        ELSE
            OKToDrawIn := TRUE;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCres}
    PROCEDURE {TPanel.}OnAllPadsDo{(PROCEDURE DoOnThePad)};
        VAR panes:  TList {OF TPane};
            pane:   TPane;

        PROCEDURE YouDo(obj: TObject);
        BEGIN
            TPad(obj).Focus;
            DoOnThePad;
        END;

        PROCEDURE YouDoOnPages(obj: TObject);
        BEGIN
            TPane(obj).Focus;
            SELF.paginatedView.DoOnPages(NOT SELF.paginatedView.workingInMargins, DoOnThePad);
            {i.e., if we're operating in the margins, do NOT focus on the interior}
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        panes := SELF.panes;
        pane := TPane(panes.First);
        PushFocus;

        IF (panes.Size = 1) AND (SELF.previewMode <> mPrvwMargins) THEN
            BEGIN
            pane.Focus;
            DoOnThePad;
            END
        ELSE
            BEGIN
            IF SELF.previewMode = mPrvwMargins THEN
                SELF.panes.Each(YouDoOnPages)
            ELSE
                SELF.panes.Each(YouDo);
            END;

        PopFocus;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S sRes}
    FUNCTION  {TPanel.}PaneShowing{(anLRect: LRect): TPane};
        VAR pane:	        TPane;
            s:		        TListScanner;
            viewedLRect:        LRect;
            scrollableLRect:    LRect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        PaneShowing := NIL;

        s := SELF.panes.Scanner;
        WHILE s.Scan(pane) DO
            BEGIN
            pane.GetScrollLimits(viewedLRect, scrollableLRect);
            WITH anLRect DO
                BEGIN
                LRectHaveLPt(scrollableLRect, topLeft);
                LRectHaveLPt(scrollableLRect, botRight);
                END;

            WITH viewedLRect DO
                IF top <= anLRect.bottom THEN
                    IF bottom >= anLRect.top THEN
                        IF left <= anLRect.right THEN
                            IF right >= anLRect.left THEN
                                BEGIN
                                s.Done;
                                PaneShowing := pane;
                                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TPanel.}PaneToScroll(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER): TPane;
        VAR tempLRect:	    LRect;
            pane:	    TPane;
            dummyPt:	    Point;
    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        WITH anLRect DO
            BEGIN
            tempLRect.top := top + vMinToSee;
            tempLRect.bottom := bottom - vMinToSee;
            tempLRect.left := left + hMinToSee;
            tempLRect.right := right - hMinToSee;
            END;

        pane := SELF.PaneShowing(tempLRect);

        IF pane = NIL THEN
            BEGIN
            pane := SELF.PaneShowing(anLRect);

            IF pane = NIL THEN
                WITH SELF.lastClick DO
                    BEGIN
                    IF NOT gotPane THEN
                        BEGIN
                        {$H-}
                        clickPane := TPane(SELF.ChildWithPt(clickPt, SELF.panes, dummyPt));
                        {$H+}
                        gotPane := TRUE;
                        END;
                    pane := clickPane;
                    END;
            END
        ELSE
            pane := NIL; {already showing The Right Stuff}

        PaneToScroll := pane;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TPanel.}Preview{(newMode: TPreviewMode)};
        VAR oldMode:	        TPreviewMode;
            showMargins:        BOOLEAN;
            hideMargins:        BOOLEAN;
            noSelection:        TSelection;
            paginatedView:      TPaginatedView;
            vhs:	        VHSelect;
            offset:	        LPoint;
            bs:		        TListScanner;
            band:	        TBand;
            firstPane:	        TPane;
            pagiLPoint:	        LPoint;
            ps:		        TListScanner;
            pane:	        TPane;
            pageEditView:       TView;
            unPagLPt:	        LPoint;	    {and pageLocation out!}

        PROCEDURE XorBreaksOnThePad;
        BEGIN
            SELF.view.printManager.DrawBreaks(FALSE);
        END;

        PROCEDURE ClearSelection;
        BEGIN
            noSelection := SELF.selection.FreedAndReplacedBy(SELF.view.NoSelection);
        END;

    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF SELF.view.isPrintable THEN   {Actually shouldn't be called unless isPrintable}
            BEGIN
            oldMode := SELF.previewMode;

            showMargins := (newMode = mPrvwMargins);
            hideMargins := (oldMode = mPrvwMargins);

            IF oldMode = newMode THEN
                BEGIN
                END
            ELSE
            IF showMargins OR hideMargins  THEN
                BEGIN

                paginatedView := SELF.paginatedView;

                IF showMargins THEN
                    BEGIN
                    paginatedView := SELF.view.printManager.NewPaginatedView(NIL);
                    SELF.currentView := paginatedView;
                    SELF.paginatedView := paginatedView;
                    END
                ELSE
                    SELF.currentView := SELF.view; { newMode = show Breaks or show main view }

                SELF.previewMode := newMode;

                FOR vhs := v TO h DO
                    BEGIN
                    offset.vh[orthogonal[vhs]] := 0;
                    bs := SELF.bands[vhs].Scanner;
                    WHILE bs.Scan(band) DO
                        BEGIN
                        firstPane := TPane(band.panes.First);
                        IF showMargins THEN
                            paginatedView.PagifyLPoint(firstPane.viewedLRect.topLeft, pagiLPoint)
                        ELSE
                        IF hideMargins THEN
                            paginatedView.DePagifyLPoint(firstPane.viewedLRect.topLeft, pagiLPoint);

                        offset.vh[vhs] := pagiLPoint.vh[vhs] - firstPane.viewedLRect.topLeft.vh[vhs];
                        ps := band.panes.Scanner;
                        WHILE ps.Scan(pane) DO
                            BEGIN
                            pane.currentView := SELF.currentView;
                            pane.OffsetBy(offset);
                            END;
                        END;
                    END;

                IF hideMargins THEN
                    BEGIN
                    paginatedView.Free;
                    SELF.paginatedView := NIL;
                    theMarginPad.view := NIL;
                    END;

                SELF.Rescroll;  {Does Invalidate and Moves Thumbs}
                END
            ELSE
                BEGIN
                SELF.window.Update(TRUE);	      {Update in the old mode, in case regions were invalid}
                SELF.previewMode := newMode;    {Set the new mode}
                SELF.OnAllPadsDo(XorBreaksOnThePad);    {Xor the page breaks}
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


   {$S SgABCpri}
        PROCEDURE {TPanel.}PrintView{(printPref: TPrReserve)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.view.printManager <> NIL THEN
            SELF.view.printManager.Print(printPref);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


{$S sStartup}
    PROCEDURE {TPanel.}Refresh{(rActions: TActions; highTransit: THighTransit)};

        PROCEDURE RefreshPane(obj: TObject);
            VAR pane:  TPane;
        BEGIN
            pane := TPane(obj);
            IF RectIsVisible(pane.outerRect) THEN
                pane.Refresh(rActions, highTransit);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        {$IFC fDbgABC}
        IF (rBackground IN rActions) AND (highTransit > hOffToOn) THEN
            ABCBreak('Refresh: rBackground requested, but highTransit does not start from Off', 0);
        {$ENDC}
        IF rFrame IN rActions THEN
            SELF.Frame;
        SELF.panes.Each(RefreshPane);
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}RemakePanes;
        VAR vs, ps: TListScanner;
            band: TBand;
            pane: TPane;
    BEGIN
    {assumes they are right in the bands}
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.panes.DelAll(FALSE);
        vs := SELF.bands[v].Scanner;
        WHILE vs.Scan(band) DO
            BEGIN
            ps := band.panes.Scanner;
            WHILE ps.Scan(pane) DO
                SELF.panes.insLast(pane);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}RememberSplit{(vhs: VHSelect; atCd: INTEGER)};
        VAR deletedSplits:  TArray;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        deletedSplits := SELF.deletedSplits;
        IF deletedSplits <> NIL THEN
            BEGIN
            {$IFC fDbgABC}
            IF deletedSplits.recordBytes <> 2 THEN
                ABCbreak('This panel has a deletedSplits array, but its recordBytes <> 2', ORD(SELF));
            {$ENDC}

            IF vhs = v THEN
                atCd := - atCd;
            deletedSplits.InsLast(@atCd);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}Remove;
        VAR itsParent:	    TBranchArea;
            itsGrandParent: TBranchArea;
            itsSibling:	    TArea;
            itsWindow:	    TWindow;
            firstPanel:	    TPanel;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        itsParent := SELF.parentBranch;
        itsWindow := SELF.window;

        {$IFC fDbgABC}
        IF itsParent = NIL THEN
            ABCBreak('You cannot remove the last panel in the window', ORD(SELF));
        {$ENDC}

        itsGrandParent := itsParent.parentBranch;
        itsSibling := itsParent.OtherChild(SELF);

        itsSibling.ResizeOutside(itsParent.outerRect);

        itsSibling.parentBranch := itsGrandParent;
        IF itsGrandParent = NIL THEN
            itsWindow.panelTree := itsSibling
        ELSE
            itsGrandParent.ReplaceChild(itsParent, itsSibling); {also sets my parentBranch to NIL}

        SELF.resizeBranch := NIL;

        firstPanel := TPanel(itsWindow.panels.First);
        IF itsWindow.selectPanel = SELF THEN
            itsWindow.selectPanel := firstPanel;
        IF itsWindow.clickPanel = SELF THEN
            itsWindow.clickPanel := firstPanel;
        {We do not change undoSelPanel & undoClickPanel because undo may bring them back; so caller beware!}
        itsParent.Free;

        itsWindow.panels.DelObject(SELF, FALSE);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}RepaneOrthogonalBands{(vhs: VHSelect)};
        VAR bs, orthoBs, ps: TListScanner;
            orthoBands:	 TList;
            band, oBand: TBand;
            pane: TPane;
    BEGIN
    {assumes they are right in the orthogonal band}
        {$IFC fTrace}BP(7);{$ENDC}
        orthoBands := SELF.bands[orthogonal[vhs]];
        orthoBs := orthoBands.Scanner;
        while orthoBs.Scan(oBand) do
            oBand.panes.DelAll(FALSE);
        bs := SELF.bands[vhs].Scanner;
        WHILE bs.Scan(band) DO
            BEGIN
            ps := band.panes.Scanner;
            orthoBs := orthoBands.Scanner;
            WHILE ps.Scan(pane) AND orthoBs.Scan(oBand) DO
                oBand.panes.insLast(pane);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}Replace{(panel: TPanel)};
        VAR itsParent:	    TBranchArea;
            itsWindow:	    TWindow;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        itsParent := SELF.parentBranch;
        itsWindow := SELF.window;

        itsWindow.panels.DelObject(SELF, FALSE);
        itsWindow.panels.InsLast(panel);

        IF itsParent = NIL THEN
            itsWindow.panelTree := panel
        ELSE
            itsParent.ReplaceChild(SELF, panel); {also sets my parentBranch to NIL}

        SELF.resizeBranch := NIL;

        panel.ResizeOutside(SELF.outerRect);

        IF itsWindow.selectPanel = SELF THEN
            itsWindow.selectPanel := panel;
        IF itsWindow.clickPanel = SELF THEN
            itsWindow.clickPanel := panel;
        {We do not change undoSelPanel & undoClickPanel because undo may bring them back; so caller beware!}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TPanel.}Rescroll;
        VAR vhs:    VHSelect;
            band:   TBand;
            s:	    TListScanner;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        InvalRect(SELF.outerRect);  {Since the view is changing, no part of the old image is good}
        FOR vhs := v TO h DO
            BEGIN
            s := SELF.bands[vhs].Scanner;
            WHILE s.Scan(band) DO
                IF band.scroller <> NIL THEN
                    SetThumb(POINTER(band.scroller.sBoxID), band.ThumbPos);
                        {since we invalidated everything, just telling the SB library where the
                            thumb should be is enough}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}ResizeBand{(vhs: VHSelect; band: TBand; newViewLCd: LONGINT;
                                     fInvalidate: BOOLEAN)};
        VAR scroller:	    TScroller;
            sbRect:	    Rect;
            tempRect:	    Rect;
            toBeDeleted:    TList {OF TPane};
            ps:		    TListScanner;
            pane:	    TPane;
            oldBandInner:   Rect;
            newOuterRect:   Rect;
            unchangedRect:  Rect;
            tempBand:	    TBand;
            sideBand:	    TSideBand;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        scroller := band.scroller;

        IF scroller = NIL THEN {band is a side band}
            sbRect := band.outerRect
        ELSE
            BEGIN
            scroller.GetSize(sbRect);
            WITH sbRect DO {regular bands must lie within the contentRect; the +/- 1 is
                                because the contentRect corresponds to the innerRect, but
                                sbRect must be based on the outerRect}
                BEGIN
                topLeft.vh[vhs] := Max(topLeft.vh[vhs], SELF.contentRect.topLeft.vh[vhs] - 1);
                botRight.vh[vhs] := Min(botRight.vh[vhs], SELF.contentRect.botRight.vh[vhs] + 1);
                END;
            END;

        unchangedRect := zeroRect;

        IF LengthRect(sbRect, vhs) <= 0 THEN
            BEGIN
            toBeDeleted := TList.CREATE(NIL, SELF.Heap, band.panes.size);
            ps := band.panes.Scanner;
            WHILE ps.Scan(pane) DO
                toBeDeleted.InsLast(pane);
            SELF.bands[vhs].DelObject(band, TRUE);
            SELF.CleanUpPanes(toBeDeleted);
            END
        ELSE
            BEGIN
            newOuterRect := SELF.innerRect;
            InsetRect(newOuterRect, -1, -1);
            AlignRect(newOuterRect, sbRect, vhs);
            oldBandInner := band.innerRect;
            band.SetOuterRect(newOuterRect);
            band.ResizePanes(newViewLCd);

            IF fInvalidate THEN
                IF band.ViewLCd = newViewLCd THEN
                    IF SectRect(oldBandInner, band.innerRect, unchangedRect) THEN;
            END;

        IF fInvalidate THEN
            InvalDiffRect(band.outerRect, unchangedRect);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TPanel.}ResizeInside{(newInnerRect: Rect)};
        VAR toBeDeleted:        TList {OF TPane};
            allBandOuterRect:   Rect;
            vhs:	        VHSelect;
            s:		        TListScanner;
            nextTopLeft:        INTEGER;
            lastBotRight:       INTEGER;
            thisBotRight:       INTEGER;
            band:	        TBand;
            ps:		        TListScanner;
            pane:	        TPane;
            newBandOuterRect:   Rect;
            oldViewLCd:	        LONGINT;
            firstBand:	        TBand;
            lastBand:	        TBand;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        toBeDeleted := TList.CREATE(NIL, SELF.Heap, 0);
        allBandOuterRect := newInnerRect;
        InsetRect(allBandOuterRect, -1, -1);
        FOR vhs := v TO h DO
            BEGIN
            firstBand := TBand(SELF.bands[vhs].First);
            IF firstBand.scroller = NIL THEN
                firstBand := TSideBand(firstBand).CoBand;
            lastBand := TBand(SELF.bands[vhs].Last);
            IF lastBand.scroller = NIL THEN
                lastBand := TSideBand(lastBand).CoBand;

            {$H-}
            WITH SELF.contentRect DO
                BEGIN
                nextTopLeft := Max(topLeft.vh[vhs]-1, allBandOuterRect.topLeft.vh[vhs]);
                lastBotRight := Min(botRight.vh[vhs]+1, allBandOuterRect.botRight.vh[vhs]);
                END;
            {$H+}

            s := SELF.bands[vhs].Scanner;
            WHILE s.Scan(band) DO
                IF band.scroller = NIL THEN {a side band}
                    BEGIN
                    IF NOT TSideBand(band).topOrLeft THEN {a bottom/right side band must be moved
                                                                into a new position}
                        BEGIN
                        SELF.SideBandRect(vhs, FALSE, newBandOuterRect); {.SideBandRect returns an InnerRect}
                        InsetRect(newBandOuterRect, -1, -1); {outerRect is innerRect outset by 1...}
                        WITH newBandOuterRect.topLeft DO
                            vh[vhs] := vh[vhs] + 1;	    {... EXCEPT on the top/left}

                        band.ResizeOutside(newBandOuterRect);
                        END;
                    END
                ELSE {a regular band}
                    {Always leave at least one pane}
                    IF (band <> firstBand) AND (nextTopLeft >= lastBotRight) THEN
                        BEGIN
                        ps := band.panes.Scanner;
                        WHILE ps.Scan(pane) DO
                            IF toBeDeleted.Pos(0, pane) <= 0 THEN
                                toBeDeleted.InsLast(pane);
                        SELF.RememberSplit(vhs, band.outerRect.topLeft.vh[vhs]);
                        s.Delete(TRUE);
                        END
                    ELSE
                        BEGIN
                        newBandOuterRect.topLeft.vh[vhs] := nextTopLeft;
                        IF band = lastBand THEN
                            thisBotRight := lastBotRight
                        ELSE
                            thisBotRight := Min(nextTopLeft + lengthRect(band.outerRect, vhs), lastBotRight);
                        newBandOuterRect.botRight.vh[vhs] := thisBotRight;
                        AlignRect(newBandOuterRect, allBandOuterRect, orthogonal[vhs]);
                        oldViewLCd := band.ViewLCd;
                        band.ResizeOutside(newBandOuterRect);
                        IF oldViewLCd <> band.ViewLCd THEN
                            InvalRect(band.innerRect);
                        nextTopLeft := newBandOuterRect.botRight.vh[vhs];
                        END;
            END;
        SELF.CleanUpPanes(toBeDeleted);
        SELF.RestoreSplits; {do this after all the bands have been adjusted}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}ResizeOutside{(newOuterRect: Rect)};
        VAR oldOuterRect:   Rect;
            oldInnerRect:   Rect;
            newInnerRect:   Rect;
            unchangedRect:  Rect;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        oldOuterRect := SELF.outerRect;

        IF NOT EqualRect(oldOuterRect, newOuterRect) THEN
            BEGIN
            oldInnerRect := SELF.innerRect;
            SELF.DecideAboutBars(newOuterRect);
            newInnerRect := SELF.innerRect;

            unchangedRect := zeroRect;
            IF EqualPt(oldOuterRect.topLeft, newOuterRect.topLeft) THEN
                IF SectRect(oldInnerRect, newInnerRect, unchangedRect) THEN;

            InvalDiffRect(newOuterRect, unchangedRect);

            SELF.ResizeInside(newInnerRect);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TPanel.}RestoreSplits;
        VAR deletedSplits:  TArray;
            contentRect:    Rect;
            vhs:	    VHSelect;
            firstScrollers: ARRAY[VHSelect] OF TScroller;
            s:		    TArrayScanner;
            pInt:	    Ptr;
            cd:		    INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        deletedSplits := SELF.deletedSplits;

        IF deletedSplits <> NIL THEN
            BEGIN
            {$IFC fDbgABC}
            IF deletedSplits.recordBytes <> 2 THEN
                ABCbreak('This panel has a deletedSplits array, but its recordBytes <> 2', ORD(SELF));
            {$ENDC}

            contentRect := SELF.contentRect;
            FOR vhs := v TO h DO
                firstScrollers[vhs] := SELF.scrollBars[vhs].firstBox;

            s := deletedSplits.Scanner;
            WHILE s.Scan(pInt) DO
                BEGIN
                cd := TpInteger(pInt)^;

                IF cd < 0 THEN
                    BEGIN
                    vhs := v;
                    cd := - cd;
                    END
                ELSE
                    vhs := h;

                IF (cd > contentRect.topLeft.vh[vhs]) AND
                   (cd < contentRect.botRight.vh[vhs] - dptSkewer.vh[vhs]) THEN
                    BEGIN
                    SELF.MoveSplitBefore(firstScrollers[vhs], cd);
                    s.Delete;
                    END;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sRes}
    PROCEDURE {TPanel.}RevealLRect(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER);
        VAR pane:	    TPane;
            revisedLRect:   LRect;
    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        IF SELF.previewMode = mPrvwMargins THEN {need to map coords}
            BEGIN
            SELF.paginatedView.PagifyLPt(anLRect.topLeft, revisedLRect.topLeft);
            SELF.paginatedView.PagifyLPt(anLRect.botRight, revisedLRect.botRight);
            END
        ELSE
            revisedLRect := anLRect;
        pane := SELF.PaneToScroll(revisedLRect, hMinToSee, vMinToSee);
        IF pane <> NIL THEN
            pane.ScrollToReveal(revisedLRect, hMinToSee, vMinToSee);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TPanel.}SetInnerRect{(newInnerRect: Rect)};
    BEGIN
        {$IFC fTrace}BP(11);{$ENDC}
        SUPERSELF.SetInnerRect(newInnerRect);
        SELF.ComputeContentRect;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TPanel.}SetOuterRect{(newOuterRect: Rect)};
    BEGIN
        {$IFC fTrace}BP(11);{$ENDC}
        SUPERSELF.SetOuterRect(newOuterRect);
        SELF.ComputeContentRect;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TPanel.}SetZoomFactor{(zoomNumerator, zoomDenominator: Point)};
        VAR s:	    TListScanner;
            pane:   TPane;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        Reduce(zoomNumerator.h, zoomDenominator.h); {reduce to lowest terms}
        Reduce(zoomNumerator.v, zoomDenominator.v); {reduce to lowest terms}
        {$IFC fDbgABC}
        IF fExperimenting THEN
            WriteLn('New (h) Zoom: ', zoomNumerator.h:1, '/', zoomDenominator.h:1);
        {$ENDC}
        WITH SELF, zoomFactor DO
            BEGIN
            numerator := zoomNumerator;
            denominator := zoomDenominator;
            zoomed := (numerator.h <> denominator.h) OR (numerator.v <> denominator.v);
            END;
        s := SELF.panes.Scanner;
        WHILE s.Scan(pane) DO
            pane.SetZoomFactor(zoomNumerator, zoomDenominator);
        SELF.Rescroll;  {Does Invalidate and Moves Thumbs}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


{$S SgABCcld}
    PROCEDURE {TPanel.}ShowSideBand{(vhs: VHSelect; topOrLeft: BOOLEAN; size: INTEGER; viewLCd: LONGINT)};
        VAR x:		    INTEGER;
            bandIndex:	    INTEGER;
            band:	    TBand;
            contentRect:    Rect;
            tempRect:	    Rect;
            oldSideSize:    INTEGER;
            newViewLCd:	    LONGINT;
            scroller:	    TScroller;
            s:		    TListScanner;
            bandVHS:	    VHSelect;
            bandIsCovered:  BOOLEAN;
            moveNextSplit:  BOOLEAN;
            removeCd:	    INTEGER;
            coBand:	    TBand;

    BEGIN
        {$IFC fTrace}BP(12);{$ENDC}
        SELF.SideBandRect(vhs, topOrLeft, tempRect);
        oldSideSize := LengthRect(tempRect, vhs);
        x := Max(-1, size);

        WITH SELF DO
            IF topOrLeft THEN
                tlSideBandSize.vh[vhs] := x
            ELSE
                brSideBandSize.vh[vhs] := x;

        SELF.ComputeContentRect;

        IF size > oldSideSize THEN
            BEGIN
            SELF.window.Resize(FALSE); {make sure we have enough space for the bigger side band}

            { delete splits that are now covered by the bigger side band }
            IF topOrLeft THEN
                removeCd := 0
            ELSE
                removeCd := MAXINT;

            moveNextSplit := FALSE;
            s := SELF.bands[vhs].Scanner;

            WHILE s.Scan(band) DO
                IF band.scroller <> NIL THEN {not a side band}
                    BEGIN
                    bandIsCovered := NOT SectRect(band.innerRect, SELF.contentRect, tempRect);

                    IF bandIsCovered THEN
                        s.Delete(FALSE); {delete it from the list before some other method, so our scanner
                                            doesn't get confused; it will still get freed later, though}

                    IF moveNextSplit OR (bandIsConvered AND NOT topOrLeft) THEN
                        BEGIN
                        SELF.RememberSplit(vhs, band.outerRect.topLeft.vh[vhs]);
                        SELF.MoveSplitBefore(band.scroller, removeCd);
                        END;

                    moveNextSplit := bandIsCovered AND topOrLeft;
                    END;
            END;

        SELF.SideBandRect(vhs, topOrLeft, tempRect);

        {Create/Resize/Delete the sideBand}
        IF (oldSideSize = -1) AND (size >= 0) THEN {create}
            BEGIN
            band := TSideBand.CREATE(NIL, SELF.Heap, SELF, tempRect, vhs, topOrLeft, viewLCd);
            coBand := TSideBand(band).Coband;

            InvalRect(tempRect);

            SELF.RepaneOrthogonalBands(vhs);
            SELF.RemakePanes;

            {calculate the new viewLCd for the side band's coBand}
            newViewLCd := coBand.ViewLCd;
            IF topOrLeft THEN
                newViewLCd := newViewLCd + size + 1;
            END
        ELSE IF oldSideSize >= 0 THEN
            BEGIN
            IF topOrLeft THEN {get the side band to resize into band}
                band := TBand(SELF.bands[vhs].First)
            ELSE
                band := TBand(SELF.bands[vhs].Last);
            coband := TSideBand(band).Coband;

            band.SetInnerRect(tempRect); {side bands are resized according to their current inner/outerRects}
            SELF.ResizeBand(vhs, band, band.ViewLCd, TRUE);

            {calculate the new viewLCd for the side band's coBand}
            newViewLCd := coBand.ViewLCd;
            IF topOrLeft THEN
                newViewLCd := newViewLCd + size - oldSideSize;
            END
        ELSE
            coBand := NIL;

        IF coBand <> NIL THEN
            BEGIN
            {resize the regular band that is next to the sideBand (coband)}
            SELF.ResizeBand(vhs, coBand, newViewLCd, TRUE);

            {invalidate the scroller associated with coBand}
            coBand.scroller.GetSize(tempRect);
            InvalRect(tempRect);

            SELF.RestoreSplits;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TPanel.}SideBandRect{(vhs: VHSelect; topOrLeft: BOOLEAN; VAR bandRect: Rect)};
        {gets the innerRect of a side band, given the current contentRect}
        VAR contentRect:    Rect;
    BEGIN
        bandRect := SELF.innerRect;
        WITH bandRect DO
            IF topOrLeft THEN
                botRight.vh[vhs] := topLeft.vh[vhs] + SELF.tlSideBandSize.vh[vhs]
            ELSE
                topLeft.vh[vhs] := botRight.vh[vhs] - SELF.brSideBandSize.vh[vhs];
    END;


{$S SgABCini}
END;
{$S SgABCres}


METHODS OF TBand;


    {$S sCldInit}
    FUNCTION  {TBand.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
                           itsScroller: TScroller; itsDir: VHSelect): TBand};
        VAR panes: TList;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TBand(object);

        WITH SELF DO
            BEGIN
            window := itsPanel.window;
            panel := itsPanel;
            scroller := itsScroller;
            scrollDir := itsDir;
            parentBranch := NIL;
            END;
        panes := TList.CREATE(NIL, heap, 1);
        SELF.panes := panes;
        SELF.SetInnerRect(itsInnerRect);
        IF itsScroller <> NIL THEN
            itsScroller.band := SELF;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCini}
    PROCEDURE {TBand.}Free;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        Free(SELF.scroller);
        SELF.panes.FreeObject;
        TArea.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TBand.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TArea.Fields(Field);
        Field('window: TWindow');
        Field('panes: TList');
        Field('panel: TPanel');
        Field('scroller: TScroller');
        Field('scrollDir: Byte');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sScroll}
    PROCEDURE {TBand.}OffsetPanes{(deltaLPt: LPoint)};

        PROCEDURE YouOffset(obj: TObject);
        BEGIN
            TPane(obj).OffsetBy(deltaLPt);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.panes.Each(YouOffset);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TBand.}ResizeOutside{(newOuterRect: Rect)};
        VAR scroller:	        TScroller;
            newScrollerSize:    Rect;
            unchangedRect:      Rect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF NOT EqualRect(SELF.outerRect, newOuterRect) THEN
            BEGIN
            unchangedRect := SELF.outerRect;
            IF NOT EqualPt(unchangedRect.topLeft, newOuterRect.topLeft) THEN
                unchangedRect := zeroRect
            ELSE
                InsetRect(unchangedRect, 1, 1); {we want unchangedRect to be the old innerRect}
            InvalDiffRect(newOuterRect, unchangedRect);

            scroller := SELF.scroller;
            SELF.SetOuterRect(newOuterRect);

            newScrollerSize := SELF.outerRect;
            WITH SELF DO
                BEGIN
                newScrollerSize.botRight.vh[orthogonal[scrollDir]] :=
                    panel.innerRect.botRight.vh[orthogonal[scrollDir]] + 1;

                IF innerRect.topLeft.vh[scrollDir] = panel.contentRect.topLeft.vh[scrollDir] THEN
                    newScrollerSize.topLeft.vh[scrollDir] := panel.innerRect.topLeft.vh[scrollDir] - 1;

                IF innerRect.botRight.vh[scrollDir] = panel.contentRect.botRight.vh[scrollDir] THEN
                    newScrollerSize.botRight.vh[scrollDir] := panel.innerRect.botRight.vh[scrollDir] + 1;
                END;
            scroller.SetSize(newScrollerSize);

            SELF.ResizePanes(SELF.ViewLCd);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TBand.}ResizePanes{(newViewLCd: LONGINT)};
    {assumes SELF.innerRect already set}
        VAR vhs:	      VHSelect;
            s:		      TListScanner;
            pane:	      TPane;
            viewedLRect:      LRect;
            scrollableLRect:  LRect;
            oldViewLCd:	      LONGINT;
            deltaLPt:	      LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        vhs := SELF.scrollDir;

        s := SELF.panes.Scanner;
        WHILE s.Scan(pane) DO
            pane.Resize(SELF.innerRect, vhs);

        IF SELF.panel.currentView <> NIL THEN
            BEGIN
            pane := TPane(SELF.panes.First);
            pane.GetScrollLimits(viewedLRect, scrollableLRect);
            oldViewLCd := SELF.ViewLCd;
            newViewLCd := Max(scrollableLRect.topLeft.vh[vhs],
                             Min(scrollableLRect.botRight.vh[vhs] - LengthLRect(viewedLRect, vhs),
                                 newViewLCd));

            deltaLPt.vh[orthogonal[vhs]] := 0;
      {$H-} deltaLPt.vh[vhs] := newViewLCd - oldViewLCd; {$H+}
            SELF.OffsetPanes(deltaLPt);
            SELF.ScrollBy(0);
            SetThumb(POINTER(SELF.scroller.sBoxID), SELF.ThumbPos);
                {need to set thumb because band changed size}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sScroll}
    PROCEDURE {TBand.}ScrollBy{(deltaLCd: LONGINT)};
        {positive scrolls towards end; 0 means resize & don't move thumb}
        VAR deltaLPt:   LPoint;
            vhs:        VHSelect;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        PushFocus;
        SELF.window.Focus;

        WITH SELF, deltaLPt DO
           BEGIN
           vhs := scrollDir;
           vh[vhs] := deltaLCd;
           vh[orthogonal[vhs]] := 0;
           END;

        SELF.panel.DoScrolling(SELF, TPane(SELF.panes.First), vhs=h, vhs=v, deltaLPt);

        IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
            SELF.OffsetPanes(deltaLPt);

        IF deltaLCd <> 0 THEN
            IF SELF.scroller <> NIL THEN {can this be a side band???}
                SELF.scroller.MoveThumb(SELF.ThumbPos);

        PopFocus;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TBand.}ScrollStep{(icon: TEnumIcons; deltaLStd: LONGINT)};
        VAR vhs:        VHSelect;
            len:        LONGINT;
            deltaLCd:   LONGINT;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        vhs := SELF.scrollDir;
        len := LIntDivInt(LengthRect(SELF.innerRect, vhs) * ORD4(SELF.panel.view.res.vh[vhs]),
                        screenRes.vh[vhs]);

        CASE icon OF  {how far to scroll without regard for overshooting the ends}
            iScrollBack:
                deltaLCd := -deltaLStd;
            iScrollFwd:
                deltaLCd := deltaLStd;
            iFlipBack:
                deltaLCd := Min(deltaLStd - len, -deltaLStd);
            iFlipFwd:
                deltaLCd := Max(len - deltaLStd, deltaLStd);
            END;
        SELF.ScrollBy(deltaLCd);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TBand.}ScrollTo{(viewLCd: LONGINT)};
        VAR pane:       TPane;
            deltaLCd:   LONGINT;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        pane := TPane(SELF.panes.First);
        deltaLCd := viewLCd  - pane.viewedLRect.topLeft.vh[SELF.scrollDir];
        SELF.ScrollBy(deltaLCd);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    FUNCTION  {TBand.}ThumbPos{: INTEGER};
        VAR vhs:	        VHSelect;
            pane:	        TPane;
            viewedLRect:        LRect;
            scrollableLRect:    LRect;
            thumbLRange:        LONGINT;
            barRange:	        INTEGER;
            lOffset:	        LONGINT;
            barPos:	        INTEGER;
    BEGIN
        {$IFC fTrace}BP(4);{$ENDC}
        vhs := SELF.scrollDir;
        pane := TPane(SELF.panes.First);
        pane.GetScrollLimits(viewedLRect, scrollableLRect);
        thumbLRange := LengthLRect(scrollableLRect, vhs) - LengthLRect(viewedLRect, vhs);
        barRange := SELF.scroller.ThumbRange;

        IF barRange = 0 THEN
            ThumbPos := 0
        ELSE
            BEGIN
            lOffset := viewedLRect.topLeft.vh[vhs] - scrollableLRect.topLeft.vh[vhs];

            IF thumbLRange > 1 THEN			    {Only divide by positive denominators}
                barPos := LIntDivLInt(LIntMulInt(lOffset, barRange - 1) + thumbLRange - barRange,
                                                 thumbLRange - 1)
            ELSE
            IF (thumbLRange = 1) AND (lOffset > 0) THEN	    {Very rare case: view one pixel bigger
                                                             than pane...}
                barPos := barRange			    {...and scrolled to end}
            ELSE
                barPos := 0;				    {Usually because the view is smaller than the
                                                             pane}
            {barPos = 0 or barRange only if nowhere to scroll}

            ThumbPos := Max(0, Min(1000, LIntDivInt(LIntMulInt(barPos, 1000) + barRange - 1, barRange)));
              {ThumbPos = 0 or 1000 only if nowhere to scroll [assumes band is <= 1000 pixels long]}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TBand.}ThumbTo{(newThumbPos: INTEGER)};
        VAR vhs:	        VHSelect;
            thumbLRange:        LONGINT;
            pane:	        TPane;
            viewedLRect:        LRect;
            scrollableLRect:    LRect;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        vhs := SELF.scrollDir;
        pane := TPane(SELF.panes.First);
        pane.GetScrollLimits(viewedLRect, scrollableLRect);
        thumbLRange := LengthLRect(scrollableLRect, vhs) - LengthLRect(viewedLRect, vhs);
        SELF.ScrollTo(scrollableLRect.topLeft.vh[vhs] +
                        LIntDivInt(LIntMulInt(thumbLRange, newThumbPos), 1000));
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TBand.}ViewLCd{: LONGINT};
        VAR pane:   TPane;
    BEGIN
        {$IFC fTrace}BP(4);{$ENDC}
        pane := TPane(SELF.panes.First);
        ViewLCd := pane.viewedLRect.topLeft.vh[SELF.scrollDir];
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF TSideBand;

    {$S SgABCcld}
    FUNCTION  {TSideBand.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
                           itsDir: VHSelect; itsTopOrLeft: BOOLEAN;
                           itsViewLCd: LONGINT): TSideBand};
    VAR bandList:   TList;
        itsCoBand:  TBand;
        deltaLPt:   LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        TSideBand(object).topOrLeft := itsTopOrLeft; {needed to be set before SetInnerRect, which is
                                            done in TBand.CREATE}

        SELF := TSideBand(TBand.CREATE(object, heap, itsPanel, itsInnerRect, NIL, itsDir));

        bandList := itsPanel.bands[itsDir];

        IF itsTopOrLeft THEN
            BEGIN
            itsCoBand := TBand(bandList.First);
            bandList.InsFirst(SELF);
            END
        ELSE
            BEGIN
            itsCoBand := TBand(bandList.Last);
            bandList.InsLast(SELF);
            END;

        SELF.panes.Become(itsCoBand.panes.Clone(heap));
        SELF.ResizePanes(itsViewLCd);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSideBand.}Free;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SELF.scroller := NIL;   {let my coBand free the scroller}
        SUPERSELF.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;

    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TSideBand.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        {$IFC fTrace}BP(10);{$ENDC}
        SUPERSELF.Fields(Field);
        Field('topOrLeft: BOOLEAN');
        Field('');
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$ENDC}


    {$S SgABCcld}
    FUNCTION  {TSideBand.}CoBand{: TBand};
        VAR bandList:   TList;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        bandList := SELF.panel.bands[SELF.scrollDir];
        IF SELF.topOrLeft THEN
            CoBand := TBand(bandList.At(2))
        ELSE
            CoBand := TBand(bandList.At(bandList.Size-1));
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSideBand.}GetBorder{(VAR border: Rect)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SUPERSELF.GetBorder(border);
        WITH SELF, border DO
            IF topOrLeft THEN
                botRight.vh[scrollDir] := 0
            ELSE
                topLeft.vh[scrollDir] := 0;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSideBand.}ResizeOutside{(newOuterRect: Rect)};
        VAR unchangedRect:      Rect;
            rectToInval:        Rect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF NOT EqualRect(SELF.outerRect, newOuterRect) THEN
            BEGIN
            unchangedRect := SELF.outerRect;
            IF NOT EqualPt(unchangedRect.topLeft, newOuterRect.topLeft) THEN
                unchangedRect := zeroRect
            ELSE
                InsetRect(unchangedRect, 1, 1); {we want unchangedRect to be the old innerRect}

            SELF.SetOuterRect(newOuterRect);

            rectToInval := SELF.innerRect;
            InsetRect(rectToInval, -1, -1);
            InvalDiffRect(rectToInval, unchangedRect);

            SELF.ResizePanes(SELF.ViewLCd);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSideBand.}ResizePanes{(newViewLCd: LONGINT)};
    {assumes SELF.innerRect already set}
        VAR vhs:	        VHSelect;
            s:		        TListScanner;
            pane:	        TPane;
            viewedLRect:        LRect;
            scrollableLRect:    LRect;
            oldViewLCd:	        LONGINT;
            deltaLPt:	        LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        vhs := SELF.scrollDir;

        s := SELF.panes.Scanner;
        WHILE s.Scan(pane) DO
            pane.Resize(SELF.innerRect, vhs);

        oldViewLCd := SELF.ViewLCd;

        deltaLPt.vh[orthogonal[vhs]] := 0;
        deltaLPt.vh[vhs] := newViewLCd - oldViewLCd;
        SELF.OffsetPanes(deltaLPt);

        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sError}
    PROCEDURE {TSideBand.}ScrollTo{(viewLCd: LONGINT)};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        ABCBreak('Can not do TSideBand.ScrollTo', 0);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    FUNCTION  {TSideBand.}ThumbPos{: INTEGER};
    BEGIN
        {$IFC fTrace}BP(4);{$ENDC}
        ThumbPos := 0;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF TPane;


    {$S sCldInit}
    FUNCTION  {TPane.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
                             itsViewedLRect: LRect): TPane};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TPane(TPad.CREATE(object, heap, itsInnerRect, itsViewedLRect, screenRes,
                                  screenRes, POINTER(itsPanel.window.wmgrId)));

        SELF.currentView := itsPanel.currentView;  {presumably unnecessary because will be done by haveView}
        SELF.panel := itsPanel;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TPane.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TPad.Fields(Field);
        Field('currentView: TView');
        Field('panel: TPanel');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sRes}
    FUNCTION  {TPane.}CursorAt{(mousePt: Point): TCursorNumber};
        {assumes mousePt is within the pane's innerRect}
        VAR mouseLPt:   LPoint;
            panePt:     Point; {window-relative, under the coordinate system defined by pane}
    BEGIN
        {$IFC fTrace}BP(2);{$ENDC}
        PushFocus;
        panePt := mousePt;
        LocalToGlobal(panePt);
        SELF.Focus;
        GlobalToLocal(panePt); {mousePt is now adjusted for the pane's new origin}
        SELF.PtToLPt(panePt, mouseLPt);
        IF LRectHasLPt(SELF.currentView.extentLRect, mouseLPt) THEN
            CursorAt := SELF.currentView.CursorAt(mouseLPt)
        ELSE
            CursorAt := arrowCursor;
        PopFocus;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TPane.}GetScrollLimits{(VAR viewedLRect, scrollableLRect: LRect)};
        VAR extra:  Point;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        viewedLRect := SELF.viewedLRect;
        WITH SELF.currentView DO
            BEGIN
            scrollableLRect := extentLRect;
            extra := scrollPastEnd;
            END;

        WITH scrollableLRect, extra DO
            BEGIN
            right  := right + Max(0, Min(viewedLRect.right - viewedLRect.left - h, h));
            bottom := bottom + Max(0, Min(viewedLRect.bottom - viewedLRect.top - v, v));
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;



    {$S sCldInit}
    PROCEDURE {TPane.}HaveView{(view: TView)};
        VAR deltaLPt:	    LPoint;
            viewedLRect:    LRect;
            paneSize:	    Point;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.currentView := view;
        IF (view.res.h <> SELF.viewedRes.h) OR (view.res.v <> SELF.viewedRes.v) THEN
            BEGIN
            PtMinusPt(SELF.innerRect.botRight, SELF.innerRect.topLeft, paneSize);
            viewedLRect := view.extentLRect;
            viewedLRect.right := viewedLRect.left +
                LIntDivInt(ORD4(paneSize.h) * view.res.h, SELF.padRes.h);
            viewedLRect.bottom := viewedLRect.top +
                LIntDivInt(ORD4(paneSize.v) * view.res.v, SELF.padRes.v);
            SELF.Redefine(SELF.innerRect, viewedLRect, SELF.padRes, view.res, SELF.zoomFactor, SELF.port);
            END
        ELSE
            BEGIN
            SetLPt(deltaLPt, view.extentLRect.left - SELF.viewedLRect.left,
                             view.extentLRect.top - SELF.viewedLRect.top);
            SELF.OffsetBy(deltaLPt);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sRes}
    PROCEDURE {TPane.}MouseTrack{(mPhase: TMousePhase; mousePt: Point)};
        {assumes mousePt is within the pane's innerRect;
            mousePt is window-relative, (0,0)-origined}
        VAR mouseLPt:	    LPoint;
            panePt:	    Point; {window-relative, under the coordinate system defined by pane}
            currentView:    TView;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        PushFocus;

        panePt := mousePt;
        LocalToGlobal(panePt);
        SELF.Focus;
        GlobalToLocal(panePt); {mousePt is now adjusted for the pane's new origin}
        SELF.PtToLPt(panePt, mouseLPt);
        currentView := SELF.currentView;
        currentView.MouseTrack(mPhase, mouseLPt);
        PopFocus;

        { &&& we should optimize the following -- SELF.CursorAt also does the same focusing as above }
        process.ChangeCursor(SELF.CursorAt(mousePt));
        {$IFC fTrace}EP;{$ENDC}
    END;

{$S sStartup}
{+++LSR+++} {This whole method is substantially changed}
    PROCEDURE {TPane.}Refresh{(rActions: TActions; highTransit: THighTransit)};

        VAR panel:	        TPanel;
            needGray:	        BOOLEAN;
            viewExtentLRect:    LRect;
            viewedLRect:        LRect;
            tempLRect:	        LRect;

        PROCEDURE HighlightOnThePad;
        BEGIN
            panel.selection.Highlight(highTransit);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        panel := SELF.panel;

        viewExtentLRect := SELF.currentView.extentLRect;
        viewedLRect := SELF.viewedLRect;

        IF rFrame IN rActions THEN
            SELF.Frame;

        needGray := (rBackground IN rActions) AND
                    ((viewedLRect.right > viewExtentLRect.right) OR
                     (viewedLRect.bottom > viewExtentLRect.bottom));

        IF rErase IN rActions THEN
            SELF.Erase;

        IF (rDraw IN rActions) OR (highTransit <> hNone) OR needGray THEN
            BEGIN
            PushFocus;
            SELF.Focus;

            IF needGray THEN
                BEGIN
                PenNormal;
                PenSize(2, 2);

                {draw the vertical strip of gray ...}
                tempLRect := viewedLRect;
                tempLRect.left := viewExtentLRect.right;
                FillLRect(tempLRect, lPatLtGray);

                {... then the horizontal strip ...}
                tempLRect := viewedLRect;
                tempLRect.top := viewExtentLRect.bottom;
                FillLRect(tempLRect, lPatLtGray);

                {... then frame the bottom right of the view extent with a 2-pixel line outside the extent;
                    note that the topLeft does not matter}
                tempLRect.topLeft := viewedLRect.topLeft;
                tempLRect.botRight := viewExtentLRect.botRight;

                InsetLRect(tempLRect, -2, -2);
                FrameLRect(tempLRect);
                END;

            IF rDraw IN rActions THEN
                SELF.currentView.Draw;

            IF highTransit <> hNone THEN
                IF panel.previewMode = mPrvwMargins THEN
                    panel.paginatedView.DoOnPages(TRUE, HighlightOnThePad)
                ELSE
                    HighlightOnThePad;

            IF rDraw IN rActions THEN  {Page breaks after highlighting, in case highlighting doesn't XOR}
                IF panel.previewMode = mPrvwBreaks THEN	 {Xors automatic as well as manual page breaks}
                    SELF.currentView.printManager.DrawBreaks(FALSE);

            PopFocus;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S sRes}
    PROCEDURE {TPane.}Resize{(newInnerRect: Rect; vhs: VHSelect)};
        VAR innerRect:	    Rect;
            paneLongSize:   LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        innerRect := SELF.innerRect;
        AlignRect(innerRect, newInnerRect, vhs);
        SELF.SetInnerRect(innerRect);
        SELF.clippedRect := innerRect;
        SELF.DistToLDist(Point(FDiagRect(innerRect)), paneLongSize);
  {$H-} LPtPlusLPt(SELF.viewedLRect.topLeft, paneLongSize, SELF.viewedLRect.botRight); {$H+}
        SELF.availLRect := SELF.viewedLRect;
  {$H-} InsetLRect(SELF.availLRect, -8192, -8192); {$H+}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TPane.}ScrollBy(VAR deltaLPt: LPoint);
        VAR panel:      TPanel;
            deltaPt:    Point;
            vhs:        VHSelect;
            band:       TBand;
            tempPt:     Point;
    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        panel := SELF.panel;

        IF panel.panes.Size = 1 THEN
            BEGIN
            PushFocus;
            SELF.panel.window.Focus;

            panel.DoScrolling(SELF, SELF, TRUE, TRUE, deltaLPt);
            IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
                BEGIN
                SELF.OffsetBy(deltaLPt);
                FOR vhs := v TO h DO
                    panel.scrollBars[vhs].firstBox.MoveThumb(TBand(panel.bands[vhs].First).ThumbPos);
                END;

            PopFocus;
            END
        ELSE
            FOR vhs := v TO h DO
                BEGIN
                band := TBand(panel.ChildWithPt(SELF.innerRect.topLeft, panel.bands[vhs], tempPt));
                band.ScrollBy(deltaLPt.vh[vhs]);
                END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TPane.}ScrollToReveal(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER);
        VAR ptMinToSee:	    Point;
            minToSee:	    INTEGER;
            viewedLRect:    LRect;
            deltaLPt:	    LPoint;
            vhs:	    VHSelect;
            lcd:	    LONGINT;
    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        viewedLRect := SELF.viewedLRect;
        SetPt(ptMinToSee, hMinToSee, vMinToSee);

        FOR vhs := v TO h DO
            BEGIN
            minToSee := Min(LengthRect(SELF.innerRect, vhs), ptMinToSee.vh[vhs]);

            lcd := anLRect.topLeft.vh[vhs] + minToSee - viewedLRect.botRight.vh[vhs];
            IF lcd <= 0 THEN
                BEGIN
                lcd := anLRect.botRight.vh[vhs] - minToSee - viewedLRect.topLeft.vh[vhs];
                IF lcd >= 0 THEN
                    lcd := 0;
                END;
            deltaLPt.vh[vhs] := lcd;
            END;

        SELF.ScrollBy(deltaLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TPane.}SetZoomFactor{(zoomNumerator, zoomDenominator: Point)};
        VAR zoomFactor: TScaler;
            newLRight:	 LONGINT;
            newLBottom:	 LONGINT;
            newViewedLRect: LRect;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        Reduce(zoomNumerator.h, zoomDenominator.h); {reduce to lowest terms}
        Reduce(zoomNumerator.v, zoomDenominator.v);

       {adjust viewed lRect}
        newLRight := Min(
            (SELF.viewedLRect.right * zoomDenominator.h * SELF.zoomFactor.numerator.h)
                DIV ( zoomNumerator.h * SELF.zoomFactor.denominator.h),
             SELF.currentView.extentLRect.right);
        newLBottom := Min(
            (SELF.viewedLRect.bottom * zoomDenominator.v * SELF.zoomFactor.numerator.v)
               DIV ( zoomNumerator.v * SELF.zoomFactor.denominator.v),
             SELF.currentView.extentLRect.bottom);

        SetLRect(newViewedLRect, SELF.viewedLRect.left, SELF.viewedLRect.top,
                  newLRight, newLBottom);
        SetPt(zoomFactor.numerator, zoomNumerator.h, zoomNumerator.v);
        SetPt(zoomFactor.denominator, zoomDenominator.h, zoomDenominator.v);
        SELF.Redefine(SELF.innerRect, newViewedLRect, SELF.padRes, SELF.viewedRes, zoomFactor, SELF.port);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF TMarginPad;


    {$S SgABCini}
    FUNCTION {TMarginPad.}CREATE{(object: TObject; heap: THeap): TMarginPad};
        VAR bodyPad: TBodyPad;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TMarginPad(object);

        bodyPad := TBodyPad.CREATE(NIL, heap, SELF);
        SELF.bodyPad := bodyPad;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TMarginPad.}Rework{(itsView: TView; itsOrigin: Point; itsRes: Point;
                       itsPageNumber: LONGINT; itsZoomFactor: TScaler; itsPort: GrafPtr)};
        VAR itsViewedLRect:  LRect;
            printerMetrics:  TPrinterMetrics;
            bodyPad:	     TBodyPad;
            innerRect:	     Rect;

        PROCEDURE ScaleToPadSpace(printRect: Rect; VAR padRect: Rect);
            VAR padLRect: LRect;
        {NB: itsOrigin is a free var in this proc}
        BEGIN
        SetLRect(padLRect,
            LIntOvrInt(ORD4(printRect.left)   * itsRes.h * itsZoomFactor.numerator.h,   {this whole stmt}
                             printerMetrics.res.h * itsZoomFactor.denominator.h),
            LIntOvrInt(ORD4(printRect.top)    * itsRes.v * itsZoomFactor.numerator.v,
                             printerMetrics.res.v * itsZoomFactor.denominator.v),
            LIntOvrInt(ORD4(printRect.right)  * itsRes.h * itsZoomFactor.numerator.h,
                             printerMetrics.res.h * itsZoomFactor.denominator.h),
            LIntOvrInt(ORD4(printRect.bottom) * itsRes.v * itsZoomFactor.numerator.v,
                             printerMetrics.res.v * itsZoomFactor.denominator.v));
        noPad.LRectToRect(padLRect, padRect);
        OffsetRect(padRect, itsOrigin.h, itsOrigin.v);
        END;

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.view := itsView;
        printerMetrics := SELF.view.printManager.printerMetrics;
        SELF.pageNumber := itsPageNumber;

        ScaleToPadSpace(printerMetrics.paperRect, innerRect);

        SELF.Redefine(innerRect, SELF.view.printManager.paperLRect,
                                itsRes,		  {pad resolutions}
                                itsView.res,	  {viewed resolutions}
                                itsZoomFactor, itsPort);        {calls TPad's Redefine method}
      {page's 'viewed space' has same metrics as the owning view's}

        SELF.bodyPad.Recompute;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCini}
    PROCEDURE {TMarginPad.}Free;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        Free(SELF.bodyPad);
        TObject.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TMarginPad.}SetForPage{(itsPageNumber: LONGINT; itsOrigin: Point)};
        VAR innerRect:  Rect;
            newOffset:  LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.pageNumber := itsPageNumber;
        innerRect := SELF.innerRect;
        OffsetRect(innerRect, itsOrigin.h - SELF.innerRect.left, itsOrigin.v - SELF.innerRect.top);
        SELF.SetInnerRect(innerRect);
        SELF.clippedRect := innerRect;
        WITH innerRect DO
            SetLPt(newOffset, - left, - top);
        SELF.SetScrollOffset(newOffset);
        SELF.bodyPad.SetForPage(itsPageNumber);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TMarginPad.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TPad.Fields(Field);
        Field('view: TView');
        Field('pageNumber: LONGINT');
        Field('bodyPad: TBodyPad');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$IFC fDbgABC}
    {$S SgABCdbg}
    FUNCTION TMarginPad.BindHeap{(activeVsClip, doBind: BOOLEAN): THeap}; {called by HeapDump in UOBJECT2}
    BEGIN
        {$IFC fMaxTrace}BP(1);{$ENDC}
        {$IFC fMaxTrace}EP;{$ENDC}
        BindHeap := NIL;
    (*  IF activeWindowID <> 0 THEN {don't allow inactive windows to use this} -- WHY NOT????  *)
            BEGIN
            IF activeVsClip THEN
                BEGIN
    (*	        IF (currentDocument <> NIL) AND doBind THEN
                    BindHeap := currentDocument.docHeap;				       *)
                IF (boundDocument <> NIL) AND doBind THEN
                    BindHeap := boundDocument.docHeap;
                END
            ELSE
            IF currentDocument <> clipboard THEN
                IF doBind THEN
                    BEGIN
                    hadToBindClip := boundClipboard = NIL;
                    IF hadToBindClip THEN
                        clipboard.Bind;
                    BindHeap := clipboard.docHeap;
                    END
                ELSE IF hadToBindClip THEN
                    clipboard.Unbind;
            END;
    END;
    {$S SgABCres}
    {$ENDC}


    {$S SgABCcld}
    PROCEDURE {TMarginPad.}Crash;
    BEGIN   {SELF = crashPad, presumably, but in any case, someone wants this process to die, so...}
        IF isInitialized THEN
            process.Complete(FALSE);
    END;
    {$S SgABCres}


    PROCEDURE TMarginPad.SetScrollOffset(VAR newOffset: LPoint);  {+SW+}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF fExperimenting OR NOT amPrinting THEN
            SUPERSELF.SetScrollOffset(newOffset)
        ELSE
            WITH SELF DO
                BEGIN
                scrollOffset := newOffset;
                origin := zeroPt;
                cdOffset := newOffset;
                END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}


METHODS OF TBodyPad;


    {$S SgABCini}
    FUNCTION {TBodyPad.}CREATE{(object: TObject; heap: THeap; itsMarginPad: TMarginPad): TBodyPad};
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TBodyPad(object);

        SELF.marginPad := itsMarginPad;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TBodyPad.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TPad.Fields(Field);
        Field('marginPad: TMarginPad');
        Field('nonNullBody: Rect');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S SgABCpri}
    PROCEDURE {TBodyPad.}Focus;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        SELF.ClipFurtherTo(SELF.nonNullBody);
        TPad.Focus;
       {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TBodyPad.}Recompute;
        VAR myViewedLRect:  LRect;
            myInnerRect:    Rect;
            view:	    TView;
            marginPad:	    TMarginPad;
            bodyRect:	    Rect;
            printManager:   TPrintManager;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        marginPad := SELF.marginPad;
        view := marginPad.view;
        printManager := view.printManager;
        printManager.GetPageLimits(marginPad.pageNumber, myViewedLRect);

        marginPad.LRectToRect(printManager.contentLRect, myInnerRect);
        WITH marginPad.origin DO {$H-}
            OffsetRect(myInnerRect, -h, -v); {$H+}

        SELF.Redefine(myInnerRect, myViewedLRect, marginPad.padRes,
          view.res, marginPad.zoomFactor, SELF.marginPad.port);
        bodyRect.topLeft := SELF.innerRect.topLeft;
        SELF.LPtToPt(myViewedLRect.botRight, bodyRect.botRight);
        bodyRect.botRight := Point(FPtMinusPt(bodyRect.botRight, SELF.origin));

        SELF.nonNullBody := bodyRect;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TBodyPad.}SetForPage{(itsPageNumber: LONGINT)};
        VAR myViewedLRect:  LRect;
            myInnerRect:    Rect;
            bodyRect:	    Rect;
            printManager:   TPrintManager;
            newOffset:	    LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        printManager := SELF.marginPad.view.printManager;
        printManager.GetPageLimits(itsPageNumber, myViewedLRect);
        SELF.marginPad.LRectToRect(printManager.contentLRect, myInnerRect);
        WITH SELF.marginPad.origin DO {$H-}
            OffsetRect(myInnerRect, -h, -v); {$H+}

        SELF.SetInnerRect(myInnerRect);

        WITH SELF, newOffset, scaleFactor DO
            BEGIN
            viewedLRect := myViewedLRect;
            availLRect := myViewedLRect;
      {$H-} InsetLRect(availLRect, -8192, -8192);  {$H+}
            clippedRect := myInnerRect;
            IF scaled THEN
                BEGIN
      {$H-}     h := LIntOvrInt(LIntMulInt(myViewedLRect.left, numerator.h), denominator.h) {+++LSR+++}
                         - myInnerRect.left;
                v := LIntOvrInt(LIntMulInt(myViewedLRect.top, numerator.v), denominator.v) {+++LSR+++}
                        - myInnerRect.top;  {$H+}
                END
            ELSE
                BEGIN
                h := myViewedLRect.left - myInnerRect.left;
                v := myViewedLRect.top - myInnerRect.top;
                END;
            END;
        SELF.SetScrollOffset(newOffset);

        SELF.nonNullBody := SELF.innerRect;
 {$H-}  SELF.LPtToPt(myViewedLRect.botRight, SELF.nonNullBody.botRight);
        SELF.nonNullBody.botRight := Point(FPtMinusPt(SELF.nonNullBody.botRight, SELF.origin)); {$H+}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    PROCEDURE TBodyPad.SetScrollOffset(VAR newOffset: LPoint);  {+SW+}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF fExperimenting OR NOT amPrinting THEN
            SUPERSELF.SetScrollOffset(newOffset)
        ELSE
            WITH SELF DO
                BEGIN
                scrollOffset := newOffset;
                origin := zeroPt;
                cdOffset := newOffset;
                END;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}


METHODS OF TScroller;


    {$S sCldInit}
    FUNCTION  {TScroller.}CREATE{(object: TObject; heap: THeap; itsScrollBar: TScrollBar; itsId: TSBoxID)
                                 :TScroller};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TScroller(object);

        WITH SELF DO
            BEGIN
            scrollBar := itsScrollBar;
            band := NIL;
            sBoxID := itsId;
      {$H-} SetSbRefcon(POINTER(sBoxID), ORD(SELF)); {$H+}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCini}
    PROCEDURE {TScroller.}Free;
        VAR sbList: TSbList;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        PreSbList(sbList, SELF.scrollBar);
  {$H-} KillSb(sbList, POINTER(SELF.sBoxID)); {$H+}
        PostSbList(sbList, SELF.scrollBar);
        TObject.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TScroller.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
       Field('scrollBar: TScrollBar');
       Field('band: TBand');
       Field('sBoxID: LONGINT');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sScroll}
    PROCEDURE {TScroller.}FillIcon{(icon: TEnumIcons; fBlack: BOOLEAN)};
        TYPE TIconAlias =
                RECORD
                CASE INTEGER OF
                    1: (sblib: TIcon);
                    2: (abc:   TEnumIcons);
                END;
        VAR iconAlias:	 TIconAlias;
    BEGIN
        {$IFC fMaxTrace}BP(1);{$ENDC}
        {$IFC fMaxTrace}EP;{$ENDC}
        iconAlias.abc := icon;
        PaintArw(POINTER(SELF.sBoxID), iconAlias.sblib, fBlack);
    END;


    {$S sRes}
    PROCEDURE {TScroller.}GetSize{(VAR boxRect: Rect)};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        GetSbRect(POINTER(SELF.sBoxID), boxRect);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TScroller.}MoveThumb{(newThumbPos: INTEGER)};
        {NOTE: assumes we are focused on the window, NOT on a pane}
    BEGIN
        {$IFC fTrace}BP(4);{$ENDC}
        IF activeWindowID <> 0 THEN
            BEGIN
            SetupMvThumb(POINTER(SELF.sboxID));
            MoveThumb(newThumbPos);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sSplit}
    PROCEDURE {TScroller.}ResplitAt{(newSkwrCd: INTEGER; prevScroller: TScroller)};
        VAR vhs:        VHSelect;
            sbRect:     Rect;
            prevSbRect: Rect;
            hsb:        THSb;
            deltaCd:    INTEGER;
            minSize:    INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        vhs := SELF.ScrollDir;
        minSize := dptSkewer.vh[vhs];
        hsb := POINTER(SELF.sBoxID);
        GetSbRect(hsb, sbRect);
        prevScroller.GetSize(prevSbRect);

        {If either scroller to becomes too small, delete it}
        IF newSkwrCd <= prevSbRect.topLeft.vh[vhs] + minSize THEN
            newSkwrCd := prevSbRect.topLeft.vh[vhs]
        ELSE IF newSkwrCd >= sbRect.botRight.vh[vhs] - minSize THEN
            newSkwrCd := sbRect.botRight.vh[vhs];

        deltaCd := newSkwrCd - sbRect.topLeft.vh[vhs];
        AdjSplitBetween(POINTER(prevScroller.sBoxID), hsb, deltaCd);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sRes}
    FUNCTION  {TScroller.}ScrollDir{: VHSelect};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        ScrollDir := TyVHOfSb(POINTER(SELF.sBoxID));
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TScroller.}SetSize{(ownerRect: Rect)};
        VAR sbRect: Rect;
            vhs: VHSelect;
            width:  INTEGER;

                {ownerRect is the band's outerRect.
                 For v bar: top/bottom  = ownerRect top/bottom
                            left        = ownerRect right - 1
                            right       = left + dhSBox}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        vhs := orthogonal[SELF.ScrollDir];
        sbRect := ownerRect;
        sbRect.topLeft.vh[vhs] := sbRect.botRight.vh[vhs] - 1;
        IF SELF.scrollBar.isVisible THEN
            width := dptSbox.vh[vhs]
        ELSE
            width := 0;
        sbRect.botRight.vh[vhs] := sbRect.topLeft.vh[vhs] + width;

        SetSbRect(POINTER(SELF.sBoxID), sbRect);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sSplit}
    PROCEDURE {TScroller.}SplitAt{(newSkwrCd: INTEGER; VAR nextScroller: TScroller)};
        VAR newHsb: THsb;
            sbList: TSbList;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        PreSbList(sbList, SELF.scrollBar);
        SplitSb(sbList, POINTER(SELF.sBoxID), newHsb, newSkwrCd);
        PostSbList(sbList, SELF.scrollBar);
        nextScroller := TScroller.CREATE(NIL, SELF.Heap, SELF.scrollBar, ORD(newHsb));
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sScroll}
    FUNCTION  {TScroller.}ThumbRange{: INTEGER};
        VAR posts: TPosts;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        MkPosts(POINTER(SELF.sBoxID), posts);
        ThumbRange := posts[iconGryB] - posts[iconPagA] - dptThumb.vh[SELF.ScrollDir];
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sSplit}
    PROCEDURE {TScroller.}TrackSkewer{(mousePt: Point; VAR newSkwrCd: INTEGER;
                                       VAR scroller, prevScroller: TScroller)};
        VAR hsb, prevHsb:   THsb;
            sbList:	    TSbList;
            limitRect:	    Rect;
            newSkwrPt:	    Point;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        hsb := POINTER(SELF.sBoxID);
        FixRLimits(hsb, limitRect);
        AlignRect(limitRect, SELF.band.outerRect, orthogonal[SELF.ScrollDir]);
        DragSkewer(hsb, mousePt, limitRect, newSkwrPt);
        newSkwrCd := newSkwrPt.vh[SELF.ScrollDir];
        prevHsb:= HsbPrev(hsb);
        IF prevHsb = hsbNil THEN
            BEGIN
            PreSbList(sbList, SELF.scrollBar);
            hsb := HsbFromPt(sbList, newSkwrPt);
            PostSbList(sbList, SELF.scrollBar);
            IF hsb = hsbNil THEN
                scroller := NIL
            ELSE
                scroller := POINTER(RefconSb(hsb));
            prevScroller := NIL;
            END
        ELSE
            BEGIN
            scroller := SELF;
            prevScroller := POINTER(RefconSb(prevHsb));
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TScroller.}TrackThumb{(mousePt: Point; VAR oldThumbPos, newThumbPos: INTEGER)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        oldThumbPos := CThumbPos(POINTER(SELF.sBoxID));
        DragThumb(POINTER(SELF.sBoxID), mousePt, newThumbPos);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}


METHODS OF TScrollBar;


    {$S SgABCini}
    FUNCTION  {TScrollBar.}CREATE{(object: TObject; heap: THeap; vhs: VHSelect; outerRect: Rect;
                                   itsVisibility: BOOLEAN): TScrollBar};
        VAR sbList:     TSbList;
            hsb:        THSb;
            firstBox:   TScroller;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TScrollBar(object);

        InitSbList(sbList, POINTER(ORD(heap)));
        hsb := SbCreate(sbList, hsbNil, vhs, zeroPt, 0);
        PostSbList(sbList, SELF);

        firstBox := TScroller.CREATE(NIL, heap, SELF, ORD(hsb));
        SELF.firstBox := firstBox;

        SELF.ChangeVisibility(itsVisibility, outerRect, []);	   {The band's outerRect}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TScrollBar.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        Field('firstBox: TScroller');
        Field('isVisible: BOOLEAN');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sCldInit}
    PROCEDURE {TScrollBar.}ChangeVisibility{(needsBothBars: BOOLEAN;
                                             bandOuterRect: Rect; itsAbilities: TAbilities)};
        VAR hsb:	    THsb;
            scroller:	    TScroller;
            needsThisBar:   BOOLEAN;
            icons:	    TSIcon;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        needsThisBar := needsBothBars OR (aBar IN itsAbilities);
        SELF.isVisible := needsThisBar;
        icons := [];
        IF needsThisBar THEN
            BEGIN {if no bar, then no icons}
            IF aScroll IN itsAbilities THEN
                icons := icons + [iconArwA, iconArwB, iconThumb, iconPagA, iconPagB];
            IF aSplit IN itsAbilities THEN
                icons := icons + [iconSkewer];
            END;
        hsb := POINTER(SELF.firstBox.sBoxID);
        WHILE hsb <> hsbNil DO
            BEGIN
            scroller := TScroller(RefconSb(hsb));
            IF scroller.band <> NIL THEN
                bandOuterRect := scroller.band.outerRect;
            scroller.SetSize(bandOuterRect);
            SetSbIcons(hsb, icons);
            hsb := HsbNext(hsb);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    FUNCTION  {TScrollBar.}DownAt{(mousePt: Point; VAR scroller: TScroller; VAR icon: TEnumIcons): BOOLEAN};
        TYPE TIconAlias =
                RECORD
                CASE INTEGER OF
                    1: (sblib: TIcon);
                    2: (abc:   TEnumIcons);
                END;
        VAR iconAlias:	 TIconAlias;
            hsbHit:	 THSb;
            sbList:	 TSbList;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        DownAt := FALSE;

        IF SELF.isVisible THEN
            BEGIN
            PreSbList(sbList, SELF);
      {$H-} IF FSbHit(sbList, mousePt, hsbHit, iconAlias.sbLib) {$H+} THEN
                BEGIN
                DownAt := TRUE;
                scroller := POINTER(RefconSb(hsbHit));
                icon := iconAlias.abc;
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TScrollBar.}Draw;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.isVisible THEN
            PaintSbar(POINTER(SELF.firstBox.sBoxID));
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TScrollBar.}Erase;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.isVisible THEN
            EraseSBar(POINTER(SELF.firstBox.sBoxID));
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}
{$S SgABCini}

